From cb4b28e964599624ddab0aec2cf6071804fce3a9 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 13:50:34 +0100 Subject: [PATCH 01/14] feature: add coroutine configuration and smoke tests (Phase 0) (#140) Add infrastructure for C++20 coroutine support detection and testing: - Add compiler_constraints.hpp with compile-time requirements: - C++23 standard required - Coroutine support (__cpp_impl_coroutine) - std::expected support (__cpp_lib_expected) - Concepts support (__cpp_concepts) - Compiler version checks (GCC 13+, Clang 17+, MSVC 19.36+) - Add coroutine_config.hpp with feature flag auto-detection - KTH_USE_COROUTINES: main feature flag - Version detection for Boost.Asio and standalone Asio - Helper macros for conditional compilation - Add comprehensive smoke tests for coroutine support - Asio version detection tests - C++20 and coroutine support detection tests - Basic coroutine functionality tests (when enabled) - Timer, error handling, racing (||), and parallel (&&) operators - Exclude network integration tests from CI (require real TCP connections) This is Phase 0 of the coroutine migration plan, establishing the foundation for future networking code modernization. --- src/infrastructure/CMakeLists.txt | 3 + .../include/kth/infrastructure.hpp | 4 + .../infrastructure/compiler_constraints.hpp | 178 ++++++++++ .../utility/coroutine_config.hpp | 203 ++++++++++++ .../test/utility/coroutine_smoke_test.cpp | 311 ++++++++++++++++++ src/network/CMakeLists.txt | 54 +-- 6 files changed, 726 insertions(+), 27 deletions(-) create mode 100644 src/infrastructure/include/kth/infrastructure/compiler_constraints.hpp create mode 100644 src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp create mode 100644 src/infrastructure/test/utility/coroutine_smoke_test.cpp diff --git a/src/infrastructure/CMakeLists.txt b/src/infrastructure/CMakeLists.txt index 5539e63b..cec15dae 100644 --- a/src/infrastructure/CMakeLists.txt +++ b/src/infrastructure/CMakeLists.txt @@ -279,6 +279,7 @@ endif() set(kth_sources ${kth_sources} ${kth_sources_just_knuth}) set(kth_headers + include/kth/infrastructure/compiler_constraints.hpp include/kth/infrastructure/compat.h include/kth/infrastructure/compat.hpp include/kth/infrastructure/constants.hpp @@ -393,6 +394,7 @@ set(kth_headers include/kth/infrastructure/utility/track.hpp include/kth/infrastructure/utility/work.hpp include/kth/infrastructure/utility/writer.hpp + include/kth/infrastructure/utility/coroutine_config.hpp include/kth/infrastructure/wallet/cashaddr.hpp include/kth/infrastructure/wallet/dictionary.hpp @@ -660,6 +662,7 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") test/utility/serializer.cpp test/utility/byte_reader.cpp test/utility/thread.cpp + test/utility/coroutine_smoke_test.cpp test/wallet/hd_private.cpp test/wallet/hd_public.cpp diff --git a/src/infrastructure/include/kth/infrastructure.hpp b/src/infrastructure/include/kth/infrastructure.hpp index 165c0983..b67d40cd 100644 --- a/src/infrastructure/include/kth/infrastructure.hpp +++ b/src/infrastructure/include/kth/infrastructure.hpp @@ -12,6 +12,9 @@ * Maintainers: Do not include this header internal to this library. */ +// Compiler constraints - must be first to fail early on incompatible compilers +#include + #include #include #include @@ -69,6 +72,7 @@ #include #include +#include #include #include #include diff --git a/src/infrastructure/include/kth/infrastructure/compiler_constraints.hpp b/src/infrastructure/include/kth/infrastructure/compiler_constraints.hpp new file mode 100644 index 00000000..a492a9c3 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/compiler_constraints.hpp @@ -0,0 +1,178 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_COMPILER_CONSTRAINTS_HPP +#define KTH_INFRASTRUCTURE_COMPILER_CONSTRAINTS_HPP + +// ============================================================================= +// Compiler Constraints and Requirements +// ============================================================================= +// +// This header enforces compile-time constraints on the compiler and standard +// library to ensure the project builds correctly. +// +// Requirements: +// - C++23 or later +// - Coroutine support (__cpp_impl_coroutine >= 201902L) +// - std::expected support (__cpp_lib_expected >= 202202L) +// - Concepts support (__cpp_concepts >= 202002L) +// +// Compiler minimums: +// - GCC 13+ +// - Clang 17+ +// - MSVC 19.36+ (VS 2022 17.6+) +// +// ============================================================================= + +// ----------------------------------------------------------------------------- +// C++ Standard Version +// ----------------------------------------------------------------------------- + +#if __cplusplus < 202302L + #error "KTH requires C++23 or later. Please use -std=c++23 or equivalent." +#endif + +// ----------------------------------------------------------------------------- +// Coroutine Support +// ----------------------------------------------------------------------------- + +#if !defined(__cpp_impl_coroutine) || __cpp_impl_coroutine < 201902L + #error "KTH requires coroutine support (__cpp_impl_coroutine >= 201902L). " \ + "Please use a compiler with C++20 coroutine support." +#endif + +// ----------------------------------------------------------------------------- +// std::expected Support (C++23) +// ----------------------------------------------------------------------------- + +// Note: __cpp_lib_expected requires or to be included first. +// We check it after including the header below. + +// ----------------------------------------------------------------------------- +// Concepts Support +// ----------------------------------------------------------------------------- + +#if !defined(__cpp_concepts) || __cpp_concepts < 202002L + #error "KTH requires concepts support (__cpp_concepts >= 202002L). " \ + "Please use a C++20 compliant compiler." +#endif + +// ----------------------------------------------------------------------------- +// Compiler Version Checks +// ----------------------------------------------------------------------------- + +#if defined(__GNUC__) && !defined(__clang__) + // GCC + #if __GNUC__ < 13 + #error "KTH requires GCC 13 or later for full C++23 support." + #endif +#elif defined(__clang__) + // Clang + #if __clang_major__ < 17 + #error "KTH requires Clang 17 or later for full C++23 support." + #endif +#elif defined(_MSC_VER) + // MSVC + #if _MSC_VER < 1936 + #error "KTH requires MSVC 19.36 (VS 2022 17.6) or later for full C++23 support." + #endif +#endif + +// ----------------------------------------------------------------------------- +// WebAssembly / Emscripten Constraints +// ----------------------------------------------------------------------------- + +#if defined(__EMSCRIPTEN__) + // Coroutines are not yet fully supported in Emscripten/WebAssembly + #warning "WebAssembly builds may have limited coroutine support." +#endif + +// ----------------------------------------------------------------------------- +// Standard Library Headers (must be included before validation) +// ----------------------------------------------------------------------------- +// Order matters: must come before on some implementations + +#include +#include +#include +#include +#include + +// ----------------------------------------------------------------------------- +// Library Feature Checks (after including headers) +// ----------------------------------------------------------------------------- + +#if !defined(__cpp_lib_expected) || __cpp_lib_expected < 202202L + #error "KTH requires std::expected support (__cpp_lib_expected >= 202202L). " \ + "Please use a C++23 compliant standard library." +#endif + +// ----------------------------------------------------------------------------- +// Compile-Time Validation +// ----------------------------------------------------------------------------- + +namespace kth::infrastructure::constraints { +namespace detail { + +// Test coroutine support +struct test_coroutine_promise { + test_coroutine_promise() = default; + std::suspend_never initial_suspend() noexcept { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void return_void() noexcept {} + void unhandled_exception() noexcept {} + struct test_coro { + using promise_type = test_coroutine_promise; + }; + test_coro get_return_object() noexcept { return {}; } +}; + +// Test std::expected support +inline void test_expected() { + [[maybe_unused]] std::expected e = 42; + static_assert(std::is_same_v); +} + +// Test concepts support +template +concept testable_concept = requires(T t) { + { t } -> std::convertible_to; +}; + +static_assert(testable_concept, "Concepts must work"); + +} // namespace detail + +// ----------------------------------------------------------------------------- +// Feature Summary (constexpr for runtime queries if needed) +// ----------------------------------------------------------------------------- + +struct compiler_info { + static constexpr int cpp_standard = __cplusplus; + static constexpr long coroutine_version = __cpp_impl_coroutine; + static constexpr long expected_version = __cpp_lib_expected; + static constexpr long concepts_version = __cpp_concepts; + +#if defined(__GNUC__) && !defined(__clang__) + static constexpr char const* compiler_name = "GCC"; + static constexpr int compiler_major = __GNUC__; + static constexpr int compiler_minor = __GNUC_MINOR__; +#elif defined(__clang__) + static constexpr char const* compiler_name = "Clang"; + static constexpr int compiler_major = __clang_major__; + static constexpr int compiler_minor = __clang_minor__; +#elif defined(_MSC_VER) + static constexpr char const* compiler_name = "MSVC"; + static constexpr int compiler_major = _MSC_VER / 100; + static constexpr int compiler_minor = _MSC_VER % 100; +#else + static constexpr char const* compiler_name = "Unknown"; + static constexpr int compiler_major = 0; + static constexpr int compiler_minor = 0; +#endif +}; + +} // namespace kth::infrastructure::constraints + +#endif // KTH_INFRASTRUCTURE_COMPILER_CONSTRAINTS_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp b/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp new file mode 100644 index 00000000..d6a2d721 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp @@ -0,0 +1,203 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_COROUTINE_CONFIG_HPP +#define KTH_INFRASTRUCTURE_COROUTINE_CONFIG_HPP + +// ============================================================================= +// Coroutine Support Detection and Configuration +// ============================================================================= +// +// This header detects whether the compiler and standard library support +// C++20 coroutines and whether Asio has the required coroutine features. +// +// Requirements for KTH_USE_COROUTINES=1: +// - C++20 or later (__cplusplus >= 202002L) +// - Compiler coroutine support (__cpp_impl_coroutine) +// - Asio 1.22+ (standalone) or Boost.Asio 1.22+ +// +// Features required from Asio: +// - asio::awaitable +// - asio::co_spawn +// - asio::use_awaitable +// - asio::experimental::channel +// - asio::experimental::awaitable_operators +// +// ============================================================================= + +#include + +// ----------------------------------------------------------------------------- +// Asio Version Detection +// ----------------------------------------------------------------------------- +// Both standalone Asio and Boost.Asio define their version in the same format: +// - ASIO_VERSION (standalone) or BOOST_ASIO_VERSION (Boost) +// - Format: XXYYZZ where: +// Major: VERSION / 100000 +// Minor: (VERSION / 100) % 1000 +// Patch: VERSION % 100 +// - Example: 103700 = version 1.37.0 +// +// Reference: https://github.com/boostorg/asio +// ----------------------------------------------------------------------------- + +#if defined(ASIO_STANDALONE) + // Standalone Asio + #include + #define KTH_ASIO_VERSION ASIO_VERSION + #define KTH_USING_STANDALONE_ASIO 1 + #define KTH_USING_BOOST_ASIO 0 +#else + // Boost.Asio + #include + #include + #define KTH_ASIO_VERSION BOOST_ASIO_VERSION + #define KTH_USING_STANDALONE_ASIO 0 + #define KTH_USING_BOOST_ASIO 1 + + // Boost version for informational purposes + #define KTH_BOOST_VERSION BOOST_VERSION + #define KTH_BOOST_VERSION_MAJOR (BOOST_VERSION / 100000) + #define KTH_BOOST_VERSION_MINOR ((BOOST_VERSION / 100) % 1000) + #define KTH_BOOST_VERSION_PATCH (BOOST_VERSION % 100) +#endif + +// Parse Asio version components +// Format: XXYYZZ -> Major.Minor.Patch +#define KTH_ASIO_VERSION_MAJOR (KTH_ASIO_VERSION / 100000) +#define KTH_ASIO_VERSION_MINOR ((KTH_ASIO_VERSION / 100) % 1000) +#define KTH_ASIO_VERSION_PATCH (KTH_ASIO_VERSION % 100) + +// ----------------------------------------------------------------------------- +// Minimum Asio Version for Coroutines +// ----------------------------------------------------------------------------- +// We require Asio 1.22+ for stable coroutine support: +// - asio::awaitable (stable since 1.18) +// - asio::co_spawn (stable since 1.18) +// - asio::experimental::channel (since 1.21) +// - asio::experimental::awaitable_operators (since 1.22) +// - asio::experimental::parallel_group (since 1.22) +// - asio::deferred (since 1.22) +// +// Version 1.22.0 = 102200 in XXYYZZ format + +#define KTH_ASIO_MIN_VERSION_FOR_COROUTINES 102200 // 1.22.0 + +// ----------------------------------------------------------------------------- +// Coroutine Support Detection +// ----------------------------------------------------------------------------- + +// Check C++ standard version +#if __cplusplus >= 202002L + #define KTH_HAS_CPP20 1 +#else + #define KTH_HAS_CPP20 0 +#endif + +// Check compiler coroutine support +#if defined(__cpp_impl_coroutine) && __cpp_impl_coroutine >= 201902L + #define KTH_HAS_COROUTINE_SUPPORT 1 +#else + #define KTH_HAS_COROUTINE_SUPPORT 0 +#endif + +// Check if Asio version is sufficient +#if KTH_ASIO_VERSION >= KTH_ASIO_MIN_VERSION_FOR_COROUTINES + #define KTH_HAS_ASIO_COROUTINES 1 +#else + #define KTH_HAS_ASIO_COROUTINES 0 +#endif + +// ----------------------------------------------------------------------------- +// Feature Flag: KTH_USE_COROUTINES +// ----------------------------------------------------------------------------- +// This is the main feature flag that enables coroutine-based networking. +// Can be: +// 1. Explicitly set by user via CMake (-DKTH_USE_COROUTINES=ON/OFF) +// 2. Auto-detected based on compiler/library support +// +// The flag is only enabled if ALL requirements are met: +// - C++20 standard +// - Compiler coroutine support +// - Sufficient Asio version +// - Not targeting Emscripten (no coroutine support in WASM yet) + +#if ! defined(KTH_USE_COROUTINES) + // Auto-detect + #if KTH_HAS_CPP20 && KTH_HAS_COROUTINE_SUPPORT && KTH_HAS_ASIO_COROUTINES && !defined(__EMSCRIPTEN__) + #define KTH_USE_COROUTINES 1 + #else + #define KTH_USE_COROUTINES 0 + #endif +#endif + +// Sanity check: if user explicitly enabled coroutines, verify requirements +#if KTH_USE_COROUTINES && !KTH_HAS_CPP20 + #error "KTH_USE_COROUTINES requires C++20 or later" +#endif + +#if KTH_USE_COROUTINES && !KTH_HAS_COROUTINE_SUPPORT + #error "KTH_USE_COROUTINES requires compiler coroutine support (__cpp_impl_coroutine)" +#endif + +#if KTH_USE_COROUTINES && !KTH_HAS_ASIO_COROUTINES + #error "KTH_USE_COROUTINES requires Asio 1.22+ or Boost.Asio 1.22+" +#endif + +// ----------------------------------------------------------------------------- +// Helper Macros for Conditional Compilation +// ----------------------------------------------------------------------------- + +#if KTH_USE_COROUTINES + #define KTH_IF_COROUTINES(...) __VA_ARGS__ + #define KTH_IF_NO_COROUTINES(...) +#else + #define KTH_IF_COROUTINES(...) + #define KTH_IF_NO_COROUTINES(...) __VA_ARGS__ +#endif + +// ----------------------------------------------------------------------------- +// Version Info Struct +// ----------------------------------------------------------------------------- + +namespace kth::infrastructure { + +struct asio_version_info { + int major; + int minor; + int patch; + int raw_version; // The raw ASIO_VERSION or BOOST_ASIO_VERSION value + bool is_standalone; + bool supports_coroutines; + +#if KTH_USING_BOOST_ASIO + int boost_major; + int boost_minor; + int boost_patch; +#endif +}; + +constexpr asio_version_info get_asio_version_info() { + return { + KTH_ASIO_VERSION_MAJOR, + KTH_ASIO_VERSION_MINOR, + KTH_ASIO_VERSION_PATCH, + KTH_ASIO_VERSION, + KTH_USING_STANDALONE_ASIO != 0, + KTH_HAS_ASIO_COROUTINES != 0 +#if KTH_USING_BOOST_ASIO + , KTH_BOOST_VERSION_MAJOR + , KTH_BOOST_VERSION_MINOR + , KTH_BOOST_VERSION_PATCH +#endif + }; +} + +constexpr bool coroutines_enabled() { + return KTH_USE_COROUTINES != 0; +} + +} // namespace kth::infrastructure + +#endif // KTH_INFRASTRUCTURE_COROUTINE_CONFIG_HPP diff --git a/src/infrastructure/test/utility/coroutine_smoke_test.cpp b/src/infrastructure/test/utility/coroutine_smoke_test.cpp new file mode 100644 index 00000000..90d5c5c0 --- /dev/null +++ b/src/infrastructure/test/utility/coroutine_smoke_test.cpp @@ -0,0 +1,311 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include + +// ============================================================================= +// Asio Version Detection Tests +// ============================================================================= + +TEST_CASE("asio version detection", "[coroutines][version]") { + auto const info = kth::infrastructure::get_asio_version_info(); + + SECTION("version is detected") { + // We should have a non-zero version if Asio is properly included + INFO("Asio version: " << info.major << "." << info.minor << "." << info.patch); + INFO("Asio raw version: " << info.raw_version); + INFO("Is standalone: " << (info.is_standalone ? "yes" : "no")); + INFO("Supports coroutines: " << (info.supports_coroutines ? "yes" : "no")); + + // At minimum, we should have Asio 1.x + CHECK(info.major >= 1); + // Raw version should be >= 100000 (1.0.0) + CHECK(info.raw_version >= 100000); + } + + SECTION("version macros are consistent") { + CHECK(info.major == KTH_ASIO_VERSION_MAJOR); + CHECK(info.minor == KTH_ASIO_VERSION_MINOR); + CHECK(info.patch == KTH_ASIO_VERSION_PATCH); + CHECK(info.raw_version == KTH_ASIO_VERSION); + } + +#if KTH_USING_BOOST_ASIO + SECTION("boost version is detected") { + INFO("Boost version: " << info.boost_major << "." << info.boost_minor << "." << info.boost_patch); + INFO("BOOST_ASIO_VERSION: " << BOOST_ASIO_VERSION); + + // We expect Boost 1.80+ for coroutine support + CHECK(info.boost_major >= 1); + + // If using Boost 1.89, Asio should be >= 1.35 + if (info.boost_major == 1 && info.boost_minor >= 89) { + CHECK(info.major == 1); + CHECK(info.minor >= 35); + } + } +#endif + +#if KTH_USING_STANDALONE_ASIO + SECTION("standalone asio is detected") { + CHECK(info.is_standalone == true); + } +#endif +} + +TEST_CASE("coroutine support detection", "[coroutines][detection]") { + SECTION("C++20 detection") { + INFO("__cplusplus = " << __cplusplus); + INFO("KTH_HAS_CPP20 = " << KTH_HAS_CPP20); + + // We compile with C++23, so this should be true + CHECK(KTH_HAS_CPP20 == 1); + } + + SECTION("compiler coroutine support") { + INFO("KTH_HAS_COROUTINE_SUPPORT = " << KTH_HAS_COROUTINE_SUPPORT); + + #if defined(__cpp_impl_coroutine) + INFO("__cpp_impl_coroutine = " << __cpp_impl_coroutine); + CHECK(KTH_HAS_COROUTINE_SUPPORT == 1); + #else + INFO("__cpp_impl_coroutine is not defined"); + #endif + } + + SECTION("asio coroutine features") { + INFO("KTH_ASIO_VERSION = " << KTH_ASIO_VERSION); + INFO("KTH_ASIO_MIN_VERSION_FOR_COROUTINES = " << KTH_ASIO_MIN_VERSION_FOR_COROUTINES); + INFO("KTH_HAS_ASIO_COROUTINES = " << KTH_HAS_ASIO_COROUTINES); + + // With Boost 1.89 or standalone Asio 1.36, we should have coroutine support + auto const info = kth::infrastructure::get_asio_version_info(); + if (info.major == 1 && info.minor >= 22) { + CHECK(KTH_HAS_ASIO_COROUTINES == 1); + } + } + + SECTION("final coroutine flag") { + INFO("KTH_USE_COROUTINES = " << KTH_USE_COROUTINES); + INFO("coroutines_enabled() = " << kth::infrastructure::coroutines_enabled()); + + CHECK(kth::infrastructure::coroutines_enabled() == (KTH_USE_COROUTINES != 0)); + + // With C++23, modern compilers, and Asio 1.36/Boost 1.89, coroutines should be enabled + #if !defined(__EMSCRIPTEN__) + // Only check if not targeting WebAssembly + auto const info = kth::infrastructure::get_asio_version_info(); + if (KTH_HAS_CPP20 && KTH_HAS_COROUTINE_SUPPORT && info.supports_coroutines) { + CHECK(KTH_USE_COROUTINES == 1); + } + #endif + } +} + +// ============================================================================= +// Coroutine Smoke Tests (only compiled when coroutines are enabled) +// ============================================================================= + +#if KTH_USE_COROUTINES + +#include +#include + +// Include the experimental headers for coroutines +#if KTH_USING_STANDALONE_ASIO +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +namespace { + +// Simple coroutine that returns a value +asio::awaitable simple_coro() { + co_return 42; +} + +// Coroutine that uses a timer +asio::awaitable timer_coro() { + auto executor = co_await asio::this_coro::executor; + asio::steady_timer timer(executor); + timer.expires_after(std::chrono::milliseconds(1)); + co_await timer.async_wait(asio::use_awaitable); + co_return 123; +} + +// Coroutine that uses as_tuple for error handling +asio::awaitable error_handling_coro() { + auto executor = co_await asio::this_coro::executor; + asio::steady_timer timer(executor); + timer.expires_after(std::chrono::milliseconds(1)); + + auto [ec] = co_await timer.async_wait(asio::as_tuple(asio::use_awaitable)); + co_return !ec; // true if no error +} + +// Coroutine using awaitable_operators (|| for racing) +asio::awaitable racing_coro() { + using namespace asio::experimental::awaitable_operators; + + auto executor = co_await asio::this_coro::executor; + + asio::steady_timer timer1(executor); + asio::steady_timer timer2(executor); + + timer1.expires_after(std::chrono::milliseconds(1)); + timer2.expires_after(std::chrono::milliseconds(100)); + + // Race: first timer to complete wins + auto result = co_await ( + timer1.async_wait(asio::use_awaitable) || + timer2.async_wait(asio::use_awaitable) + ); + + // result.index() == 0 means timer1 won (expected) + co_return static_cast(result.index()); +} + +// Coroutine using awaitable_operators (&& for parallel) +asio::awaitable parallel_coro() { + using namespace asio::experimental::awaitable_operators; + + auto executor = co_await asio::this_coro::executor; + + asio::steady_timer timer1(executor); + asio::steady_timer timer2(executor); + + timer1.expires_after(std::chrono::milliseconds(1)); + timer2.expires_after(std::chrono::milliseconds(2)); + + // Wait for both timers to complete + co_await ( + timer1.async_wait(asio::use_awaitable) && + timer2.async_wait(asio::use_awaitable) + ); + + co_return 999; // Both completed +} + +} // anonymous namespace + +TEST_CASE("coroutine smoke tests", "[coroutines][smoke]") { + asio::io_context ctx; + + SECTION("simple coroutine returns value") { + int result = 0; + asio::co_spawn(ctx, simple_coro(), [&](std::exception_ptr ep, int value) { + REQUIRE_FALSE(ep); + result = value; + }); + ctx.run(); + CHECK(result == 42); + } + + SECTION("timer coroutine works") { + int result = 0; + asio::co_spawn(ctx, timer_coro(), [&](std::exception_ptr ep, int value) { + REQUIRE_FALSE(ep); + result = value; + }); + ctx.run(); + CHECK(result == 123); + } + + SECTION("error handling with as_tuple works") { + bool result = false; + asio::co_spawn(ctx, error_handling_coro(), [&](std::exception_ptr ep, bool value) { + REQUIRE_FALSE(ep); + result = value; + }); + ctx.run(); + CHECK(result == true); + } + + SECTION("racing with || operator works") { + int result = -1; + asio::co_spawn(ctx, racing_coro(), [&](std::exception_ptr ep, int value) { + REQUIRE_FALSE(ep); + result = value; + }); + ctx.run(); + CHECK(result == 0); // First timer should win + } + + SECTION("parallel with && operator works") { + int result = 0; + asio::co_spawn(ctx, parallel_coro(), [&](std::exception_ptr ep, int value) { + REQUIRE_FALSE(ep); + result = value; + }); + ctx.run(); + CHECK(result == 999); + } +} + +TEST_CASE("coroutine exception handling", "[coroutines][exceptions]") { + asio::io_context ctx; + + SECTION("exceptions propagate correctly") { + auto throwing_coro = []() -> asio::awaitable { + throw std::runtime_error("test exception"); + co_return 0; // Never reached + }; + + bool exception_caught = false; + asio::co_spawn(ctx, throwing_coro(), [&](std::exception_ptr ep, int) { + if (ep) { + exception_caught = true; + try { + std::rethrow_exception(ep); + } catch (std::runtime_error const& e) { + CHECK(std::string(e.what()) == "test exception"); + } + } + }); + ctx.run(); + CHECK(exception_caught); + } +} + +#else // !KTH_USE_COROUTINES + +TEST_CASE("coroutines disabled", "[coroutines][disabled]") { + SECTION("KTH_USE_COROUTINES is 0") { + CHECK(KTH_USE_COROUTINES == 0); + CHECK(kth::infrastructure::coroutines_enabled() == false); + + // Log why coroutines are disabled + INFO("KTH_HAS_CPP20 = " << KTH_HAS_CPP20); + INFO("KTH_HAS_COROUTINE_SUPPORT = " << KTH_HAS_COROUTINE_SUPPORT); + INFO("KTH_HAS_ASIO_COROUTINES = " << KTH_HAS_ASIO_COROUTINES); + + #if defined(__EMSCRIPTEN__) + INFO("Reason: Emscripten target (WASM doesn't support coroutines yet)"); + #elif !KTH_HAS_CPP20 + INFO("Reason: C++20 not enabled"); + #elif !KTH_HAS_COROUTINE_SUPPORT + INFO("Reason: Compiler doesn't support coroutines"); + #elif !KTH_HAS_ASIO_COROUTINES + INFO("Reason: Asio version too old (need 1.22+)"); + #endif + } +} + +#endif // KTH_USE_COROUTINES diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 19c5a23a..2e12a6f1 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -174,33 +174,33 @@ _group_sources(${PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}") # Tests # ------------------------------------------------------------------------------ # Skip tests for WebAssembly (Catch2 incompatible with shared-memory/threads) -# TODO(fernando): Temporarily disabled for release 0.74.0 - tests take too long in CI -# if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") -# enable_testing() -# find_package(Catch2 3 REQUIRED) - -# add_executable(kth_network_test -# test/p2p.cpp -# ) - -# target_include_directories(kth_network_test PUBLIC $) - -# target_link_libraries(kth_network_test PUBLIC ${PROJECT_NAME}) -# target_link_libraries(kth_network_test PRIVATE Catch2::Catch2WithMain) - -# _group_sources(kth_network_test "${CMAKE_CURRENT_LIST_DIR}/test") - -# include(CTest) -# # Try to use Catch2 automatic test discovery -# find_package(Catch2 QUIET) -# if(Catch2_FOUND) -# include(Catch) -# catch_discover_tests(kth_network_test) -# else() -# # Fallback to manual test registration -# add_test(NAME kth_network_test COMMAND kth_network_test) -# endif() -# endif() +if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + enable_testing() + find_package(Catch2 3 REQUIRED) + + add_executable(kth_network_test + test/p2p.cpp + ) + + target_include_directories(kth_network_test PUBLIC $) + + target_link_libraries(kth_network_test PUBLIC ${PROJECT_NAME}) + target_link_libraries(kth_network_test PRIVATE Catch2::Catch2WithMain) + + _group_sources(kth_network_test "${CMAKE_CURRENT_LIST_DIR}/test") + + include(CTest) + # Try to use Catch2 automatic test discovery + find_package(Catch2 QUIET) + if(Catch2_FOUND) + include(Catch) + # Exclude [integration] tests - they require real TCP connections + catch_discover_tests(kth_network_test TEST_SPEC "~[integration]") + else() + # Fallback to manual test registration (excludes integration tests) + add_test(NAME kth_network_test COMMAND kth_network_test "~[integration]") + endif() +endif() # Install From 802e0406dc3452ec9d54c6605519462b35e421d8 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 13:53:01 +0100 Subject: [PATCH 02/14] feature: coroutine infrastructure base (Phase 1) (#141) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 of the coroutine migration. Adds base infrastructure for modern async programming with C++23 coroutines and standalone Asio 1.36.0. - `threadpool.hpp`: Rewritten using `asio::thread_pool` - `async_channel.hpp`: Type aliases for async communication channels - `async_channel`: NOT thread-safe, use with strand - `concurrent_channel`: Thread-safe for multi-threaded scenarios - `awaitable_helpers.hpp`: Coroutine utilities (with_timeout, etc.) - Added `asio_standalone` option to conanfile.py (default: True) - Added `KTH_ASIO_STANDALONE` CMake option and macro - Updated to standalone Asio 1.36.0 - Changed `.service()` → `.get_executor()` across codebase - Simplified `sequencer`, `work` classes to use modern executor API - Added comprehensive tests for threadpool stop/join behavior - Added tests for async_channel with strand serialization - Added tests for concurrent_channel multi-threaded scenarios - Added stress test with 20 producers × 10 items `asio::experimental::channel` is NOT thread-safe for concurrent access. Documentation: "Distinct objects: Safe. Shared objects: Unsafe." Use `concurrent_channel` for multi-producer/consumer scenarios. --- CMakeLists.txt | 7 + conan.lock | 8 +- conanfile.py | 12 +- src/blockchain/src/interface/block_chain.cpp | 4 +- src/infrastructure/CMakeLists.txt | 21 +- .../include/kth/infrastructure.hpp | 2 + .../include/kth/infrastructure/error.hpp | 4 +- .../infrastructure/utility/asio_helper.hpp | 10 +- .../infrastructure/utility/async_channel.hpp | 89 ++++ .../utility/awaitable_helpers.hpp | 105 +++++ .../utility/coroutine_config.hpp | 2 +- .../kth/infrastructure/utility/sequencer.hpp | 15 +- .../kth/infrastructure/utility/threadpool.hpp | 135 ++---- .../kth/infrastructure/utility/work.hpp | 62 +-- src/infrastructure/src/utility/deadline.cpp | 4 +- src/infrastructure/src/utility/sequencer.cpp | 32 +- src/infrastructure/src/utility/socket.cpp | 2 +- src/infrastructure/src/utility/threadpool.cpp | 165 -------- src/infrastructure/src/utility/work.cpp | 42 +- .../test/utility/async_channel.cpp | 399 ++++++++++++++++++ .../test/utility/awaitable_helpers.cpp | 228 ++++++++++ .../test/utility/threadpool.cpp | 227 ++++++++++ src/network/src/acceptor.cpp | 2 +- src/network/src/connector.cpp | 2 +- src/network/src/p2p.cpp | 7 +- 25 files changed, 1181 insertions(+), 405 deletions(-) create mode 100644 src/infrastructure/include/kth/infrastructure/utility/async_channel.hpp create mode 100644 src/infrastructure/include/kth/infrastructure/utility/awaitable_helpers.hpp delete mode 100644 src/infrastructure/src/utility/threadpool.cpp create mode 100644 src/infrastructure/test/utility/async_channel.cpp create mode 100644 src/infrastructure/test/utility/awaitable_helpers.cpp create mode 100644 src/infrastructure/test/utility/threadpool.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d296818..764790d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ option(WITH_CONSOLE_NODE_CINT "" OFF) option(WITH_EXAMPLES "Compile with examples." OFF) option(ENABLE_SHARED "" OFF) option(ENABLE_SHARED_NODE_CINT "" ON) +option(KTH_ASIO_STANDALONE "Use standalone Asio instead of Boost.Asio" OFF) # set(ENABLE_POSITION_INDEPENDENT_CODE ON) # set(WITH_CONSOLE OFF) @@ -54,6 +55,12 @@ if (WITH_LOCAL_MINING) add_definitions(-DWITH_LOCAL_MINING) endif() +# Asio standalone mode - define both our macro and Asio's expected macro +if (KTH_ASIO_STANDALONE) + add_definitions(-DKTH_ASIO_STANDALONE) + add_definitions(-DASIO_STANDALONE) +endif() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/ci_utils/cmake) include(KnuthTools) diff --git a/conan.lock b/conan.lock index 179b71d5..b5a9f302 100644 --- a/conan.lock +++ b/conan.lock @@ -13,15 +13,17 @@ "gmp/6.3.0#187de23af494e24e69bf9dfc1966a60d%1762775034.77", "fmt/12.0.0#dc7de7f3968e5d6b377f27b7d0f33916%1758262922.745", "ctre/3.10.0#3f970a74e5cc3ba1a8ccb8e7f513062f%1755247138.192", - "catch2/3.11.0#17ac0eaea50698d4bd1704871e90cda7%1767110221.402", + "catch2/3.11.0#a560b55882ff2deb1f4bafad832a1b98%1762775012.454", "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1763677986.008", - "boost/1.90.0#d5e8defe7355494953be18524a7f135b%1765955095.179" + "boost/1.89.0#010f59feedfd171b15f467b42f723d13%1763743419.408", + "asio/1.36.0#75a50dae6e50af10cfb2150286b7df39%1756280309.023" ], "build_requires": [ "secp256k1-precompute/1.0.0#53841449a185e25ee2337aa5e4f3583f%1751564430.278", "m4/1.4.19#b38ced39a01e31fef5435bc634461fd2%1700758725.451", "cmake/4.2.1#951586eff155256a7b5298631d6b1416%1765387599.255", - "b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1766594659.866" + "cmake/3.31.10#313d16a1aa16bbdb2ca0792467214b76%1763665505.054", + "b2/5.3.3#107c15377719889654eb9a162a673975%1750340310.079" ], "python_requires": [], "config_requires": [] diff --git a/conanfile.py b/conanfile.py index fdb2cd4e..260024b8 100644 --- a/conanfile.py +++ b/conanfile.py @@ -71,6 +71,7 @@ class KthRecipe(KnuthConanFileV2): "with_icu": [True, False], "with_png": [True, False], "with_qrencode": [True, False], + "asio_standalone": [True, False], # secp256k1 options "secp256k1_enable_coverage": [True, False], @@ -110,7 +111,8 @@ class KthRecipe(KnuthConanFileV2): "with_icu": False, "with_png": False, "with_qrencode": False, - + "asio_standalone": True, + # secp256k1 options "secp256k1_enable_coverage": False, "secp256k1_enable_branch_coverage": False, @@ -171,8 +173,8 @@ def requirements(self): if self.options.with_qrencode: self.requires("libqrencode/4.1.1", transitive_headers=True, transitive_libs=True) - # if self.options.asio_standalone: - # self.requires("asio/1.24.0", transitive_headers=True, transitive_libs=True) + if self.options.asio_standalone: + self.requires("asio/1.36.0", transitive_headers=True, transitive_libs=True) def build_requirements(self): @@ -248,6 +250,7 @@ def generate(self): tc.variables["WITH_ICU"] = option_on_off(self.options.with_icu) tc.variables["KTH_WITH_PNG"] = option_on_off(self.options.with_png) tc.variables["KTH_WITH_QRENCODE"] = option_on_off(self.options.with_qrencode) + tc.variables["KTH_ASIO_STANDALONE"] = option_on_off(self.options.asio_standalone) # Secp256k1 -------------------------------------------- tc.variables["SECP256K1_ENABLE_COVERAGE"] = option_on_off(self.options.secp256k1_enable_coverage) @@ -373,6 +376,9 @@ def package_info(self): self.cpp_info.components["infrastructure"].requires.append("libpng::libpng") if self.options.with_qrencode: self.cpp_info.components["infrastructure"].requires.append("libqrencode::libqrencode") + # Add asio when using standalone mode + if self.options.asio_standalone: + self.cpp_info.components["infrastructure"].requires.append("asio::asio") # Domain models and business logic diff --git a/src/blockchain/src/interface/block_chain.cpp b/src/blockchain/src/interface/block_chain.cpp index a43a42c6..e63ff4b6 100644 --- a/src/blockchain/src/interface/block_chain.cpp +++ b/src/blockchain/src/interface/block_chain.cpp @@ -84,7 +84,7 @@ block_chain::block_chain(threadpool& pool, blockchain::settings const& chain_set , chain_state_populator_(*this, chain_settings, network) , database_(database_settings) , validation_mutex_(relay_transactions) - , priority_pool_("blockchain", thread_ceiling(chain_settings.cores), priority(chain_settings.priority)) + , priority_pool_(thread_ceiling(chain_settings.cores)) , dispatch_(priority_pool_, NAME "_priority") #if defined(KTH_WITH_MEMPOOL) @@ -411,7 +411,7 @@ bool block_chain::stop() { auto result = transaction_organizer_.stop() && block_organizer_.stop(); // The priority pool must not be stopped while organizing. - priority_pool_.shutdown(); + priority_pool_.stop(); validation_mutex_.unlock_high_priority(); /////////////////////////////////////////////////////////////////////////// diff --git a/src/infrastructure/CMakeLists.txt b/src/infrastructure/CMakeLists.txt index cec15dae..cf503570 100644 --- a/src/infrastructure/CMakeLists.txt +++ b/src/infrastructure/CMakeLists.txt @@ -17,6 +17,7 @@ option(WITH_EXAMPLES "Compile with examples." OFF) option(WITH_ICU "Compile with International Components for Unicode." OFF) option(KTH_WITH_PNG "Compile with Libpng support." OFF) option(KTH_WITH_QRENCODE "Compile with QREncode." OFF) +option(KTH_ASIO_STANDALONE "Use standalone Asio instead of Boost.Asio" OFF) option(JUST_KTH_SOURCES "Just Knuth source code to be linted." OFF) @@ -32,6 +33,11 @@ if (KTH_WITH_QRENCODE) add_definitions(-DKTH_WITH_QRENCODE) endif() +if (KTH_ASIO_STANDALONE) + add_definitions(-DKTH_ASIO_STANDALONE) + add_definitions(-DASIO_STANDALONE) +endif() + if (JUST_KTH_SOURCES) message(STATUS "Knuth: Just Knuth source code to be linted: enabled") @@ -79,6 +85,10 @@ if (KTH_WITH_QRENCODE) find_package(libqrencode REQUIRED) endif() +if (KTH_ASIO_STANDALONE) + find_package(asio REQUIRED) +endif() + include(CheckCXXCompilerFlag) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/ci_utils/cmake) @@ -238,8 +248,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") src/utility/pseudo_random_broken_do_not_use.cpp - src/utility/threadpool.cpp - src/utility/work.cpp ) endif() @@ -394,6 +402,8 @@ set(kth_headers include/kth/infrastructure/utility/track.hpp include/kth/infrastructure/utility/work.hpp include/kth/infrastructure/utility/writer.hpp + include/kth/infrastructure/utility/async_channel.hpp + include/kth/infrastructure/utility/awaitable_helpers.hpp include/kth/infrastructure/utility/coroutine_config.hpp include/kth/infrastructure/wallet/cashaddr.hpp @@ -608,6 +618,10 @@ if (KTH_WITH_QRENCODE) target_link_libraries(${PROJECT_NAME} PUBLIC libqrencode::libqrencode) endif() +if (KTH_ASIO_STANDALONE) + target_link_libraries(${PROJECT_NAME} PUBLIC asio::asio) +endif() + target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_THREAD_LIBS_INIT}) if (MINGW) @@ -662,7 +676,10 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") test/utility/serializer.cpp test/utility/byte_reader.cpp test/utility/thread.cpp + test/utility/threadpool.cpp test/utility/coroutine_smoke_test.cpp + test/utility/awaitable_helpers.cpp + test/utility/async_channel.cpp test/wallet/hd_private.cpp test/wallet/hd_public.cpp diff --git a/src/infrastructure/include/kth/infrastructure.hpp b/src/infrastructure/include/kth/infrastructure.hpp index b67d40cd..8935a92d 100644 --- a/src/infrastructure/include/kth/infrastructure.hpp +++ b/src/infrastructure/include/kth/infrastructure.hpp @@ -117,6 +117,8 @@ #include #include #include +#include +#include #include diff --git a/src/infrastructure/include/kth/infrastructure/error.hpp b/src/infrastructure/include/kth/infrastructure/error.hpp index 945c5ca4..c90ca678 100644 --- a/src/infrastructure/include/kth/infrastructure/error.hpp +++ b/src/infrastructure/include/kth/infrastructure/error.hpp @@ -10,7 +10,7 @@ #include -#if defined(ASIO_STANDALONE) +#if defined(KTH_ASIO_STANDALONE) #include #else #include @@ -32,7 +32,7 @@ using code = std::error_code; /// Alias for boost error code declarations. -#if defined(ASIO_STANDALONE) +#if defined(KTH_ASIO_STANDALONE) using boost_code = ::asio::error_code; #else using boost_code = boost::system::error_code; diff --git a/src/infrastructure/include/kth/infrastructure/utility/asio_helper.hpp b/src/infrastructure/include/kth/infrastructure/utility/asio_helper.hpp index 574f6d25..00cecdc2 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/asio_helper.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/asio_helper.hpp @@ -5,12 +5,20 @@ #ifndef KTH_INFRASTRUCTURE_ASIO_HELPER_HPP_ #define KTH_INFRASTRUCTURE_ASIO_HELPER_HPP_ -#if defined(ASIO_STANDALONE) +#if defined(KTH_ASIO_STANDALONE) #include +#include +#include +#include +#include #else #if ! defined(__EMSCRIPTEN__) #include +#include +#include +#include +#include #else #include #endif diff --git a/src/infrastructure/include/kth/infrastructure/utility/async_channel.hpp b/src/infrastructure/include/kth/infrastructure/utility/async_channel.hpp new file mode 100644 index 00000000..97a79382 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/async_channel.hpp @@ -0,0 +1,89 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_ASYNC_CHANNEL_HPP +#define KTH_INFRASTRUCTURE_ASYNC_CHANNEL_HPP + +#include + +#include + +#if ! defined(KTH_ASIO_STANDALONE) +#include +#endif + +namespace kth { + +// ============================================================================= +// Async Channel Types +// ============================================================================= +// +// IMPORTANT: Thread Safety +// ------------------------- +// async_channel: NOT thread-safe. Use with strand or single-threaded context. +// Doc: "Distinct objects: Safe. Shared objects: Unsafe." +// concurrent_channel: Thread-safe for concurrent access from multiple threads. +// +// Usage: +// // For same-strand communication (e.g., peer_session internal queues) +// async_channel messages(strand, 10); +// +// // For multi-threaded communication (e.g., work distribution queues) +// concurrent_channel work_queue(pool.get_executor(), 100); +// +// // Producer coroutine +// co_await messages.async_send(error_code{}, "hello", use_awaitable); +// +// // Consumer coroutine +// auto [ec, msg] = co_await messages.async_receive(as_tuple(use_awaitable)); +// +// ============================================================================= + +#if defined(KTH_ASIO_STANDALONE) +// Standalone Asio uses std::error_code + +// NOT thread-safe - use with strand or single-threaded context +template +using async_channel = ::asio::experimental::channel; + +// Thread-safe - for multi-threaded producer/consumer scenarios +template +using concurrent_channel = ::asio::experimental::concurrent_channel; + +// Event channels (signaling without data) +using event_channel = ::asio::experimental::channel; +using concurrent_event_channel = ::asio::experimental::concurrent_channel; + +// Multi-value channels +template +using multi_channel = ::asio::experimental::channel; + +template +using concurrent_multi_channel = ::asio::experimental::concurrent_channel; +#else +// Boost.Asio requires boost::system::error_code for channel signatures + +// NOT thread-safe - use with strand or single-threaded context +template +using async_channel = ::asio::experimental::channel; + +// Thread-safe - for multi-threaded producer/consumer scenarios +template +using concurrent_channel = ::asio::experimental::concurrent_channel; + +// Event channels (signaling without data) +using event_channel = ::asio::experimental::channel; +using concurrent_event_channel = ::asio::experimental::concurrent_channel; + +// Multi-value channels +template +using multi_channel = ::asio::experimental::channel; + +template +using concurrent_multi_channel = ::asio::experimental::concurrent_channel; +#endif + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_ASYNC_CHANNEL_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/awaitable_helpers.hpp b/src/infrastructure/include/kth/infrastructure/utility/awaitable_helpers.hpp new file mode 100644 index 00000000..7c07d2d5 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/awaitable_helpers.hpp @@ -0,0 +1,105 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_AWAITABLE_HELPERS_HPP +#define KTH_INFRASTRUCTURE_AWAITABLE_HELPERS_HPP + +#include +#include +#include + +#include + +namespace kth { + +// ============================================================================= +// Awaitable Helpers for Coroutine-based Async Operations +// ============================================================================= + +using ::asio::awaitable; +using ::asio::use_awaitable; + +// ----------------------------------------------------------------------------- +// with_timeout: Race an operation against a timer +// ----------------------------------------------------------------------------- + +template +awaitable> with_timeout( + awaitable op, + std::chrono::milliseconds timeout +) { + using namespace ::asio::experimental::awaitable_operators; + + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + timer.expires_after(timeout); + + auto result = co_await ( + std::move(op) || + timer.async_wait(use_awaitable) + ); + + if (result.index() == 1) { + co_return std::unexpected(make_error_code(std::errc::timed_out)); + } + + co_return std::get<0>(std::move(result)); +} + +// Overload for operations that return expected +template +awaitable> with_timeout( + awaitable> op, + std::chrono::milliseconds timeout, + E timeout_error +) { + using namespace ::asio::experimental::awaitable_operators; + + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + timer.expires_after(timeout); + + auto result = co_await ( + std::move(op) || + timer.async_wait(use_awaitable) + ); + + if (result.index() == 1) { + co_return std::unexpected(timeout_error); + } + + co_return std::get<0>(std::move(result)); +} + +// ----------------------------------------------------------------------------- +// delay: Simple async sleep +// ----------------------------------------------------------------------------- + +inline awaitable delay(std::chrono::milliseconds duration) { + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + timer.expires_after(duration); + co_await timer.async_wait(use_awaitable); +} + +template +awaitable delay(std::chrono::duration duration) { + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + timer.expires_after(duration); + co_await timer.async_wait(use_awaitable); +} + +// ----------------------------------------------------------------------------- +// post_to: Execute on a specific executor +// ----------------------------------------------------------------------------- + +template +awaitable post_to(Executor&& exec) { + co_await ::asio::post(std::forward(exec), use_awaitable); +} + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_AWAITABLE_HELPERS_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp b/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp index d6a2d721..ba5f874c 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/coroutine_config.hpp @@ -42,7 +42,7 @@ // Reference: https://github.com/boostorg/asio // ----------------------------------------------------------------------------- -#if defined(ASIO_STANDALONE) +#if defined(KTH_ASIO_STANDALONE) // Standalone Asio #include #define KTH_ASIO_VERSION ASIO_VERSION diff --git a/src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp b/src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp index 71d071e2..85abcaf4 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp @@ -10,22 +10,20 @@ #include #include +#include #include #include -////#include namespace kth { -class sequencer - : public enable_shared_from_base - /*, track*/ -{ +class sequencer : public enable_shared_from_base { public: using ptr = std::shared_ptr; - using action = std::function; + using action = std::function; + using executor_type = ::asio::any_io_executor; explicit - sequencer(asio::context& service); + sequencer(executor_type executor); ~sequencer(); @@ -33,8 +31,7 @@ class sequencer void unlock(); private: - // This is thread safe. - asio::context& service_; + executor_type executor_; // These are protected by mutex. bool executing_; diff --git a/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp b/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp index 76631863..cf3d6b00 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp @@ -5,124 +5,55 @@ #ifndef KTH_INFRASTRUCTURE_THREADPOOL_HPP #define KTH_INFRASTRUCTURE_THREADPOOL_HPP -#if ! defined(__EMSCRIPTEN__) -#include #include -#include -#include #include -#include -#include -#include - -#endif - -#include +#include namespace kth { -#if ! defined(__EMSCRIPTEN__) -/** - * This class and the asio service it exposes are thread safe. - * A collection of threads which can be passed operations through io_context. - */ -class KI_API threadpool - : noncopyable -{ -public: - - /** - * Threadpool constructor, spawns the specified number of threads. - * @param[in] number_threads Number of threads to spawn. - * @param[in] priority Priority of threads to spawn. - */ - explicit - threadpool(std::string const& name, size_t number_threads = 0, thread_priority priority = thread_priority::normal); - - ~threadpool(); - - /** - * There are no threads configured in the threadpool. - */ - bool empty() const; +struct threadpool { + explicit + threadpool(size_t num_threads = std::thread::hardware_concurrency()) + : num_threads_(num_threads == 0 ? std::thread::hardware_concurrency() : num_threads) + , pool_(num_threads_) + {} - /** - * The number of threads configured in the threadpool. - */ - size_t size() const; + ~threadpool() = default; - /** - * Add the specified number of threads to this threadpool. - * @param[in] number_threads Number of threads to add. - * @param[in] priority Priority of threads to add. - */ - void spawn(size_t number_threads = 1, thread_priority priority = thread_priority::normal); + threadpool(threadpool const&) = delete; + threadpool& operator=(threadpool const&) = delete; + threadpool(threadpool&&) = delete; + threadpool& operator=(threadpool&&) = delete; - /** - * Abandon outstanding operations without dispatching handlers. - * WARNING: This call is unsave and should be avoided. - */ - void abort(); + [[nodiscard]] + ::asio::thread_pool::executor_type get_executor() { + return pool_.get_executor(); + } - /** - * Destroy the work keep alive, allowing threads be joined. - * Caller should next call join. - */ - void shutdown(); + [[nodiscard]] + ::asio::any_io_executor executor() { + return pool_.get_executor(); + } - /** - * Wait for all threads in the pool to terminate. - * This is safe to call from any thread in the threadpool or otherwise. - */ - void join(); + void stop() { + pool_.stop(); + } - /** - * Underlying boost::io_context object. - */ - asio::context& service(); + void join() { + pool_.join(); + } - /** - * Underlying boost::io_context object. - */ - const asio::context& service() const; + [[nodiscard]] + size_t size() const noexcept { + return num_threads_; + } private: - void spawn_once(thread_priority priority=thread_priority::normal); - - // This is thread safe. - asio::context service_; - - // These are protected by mutex. - - std::string name_; - std::atomic size_; - std::vector threads_; - mutable upgrade_mutex threads_mutex_; - std::shared_ptr work_; - mutable upgrade_mutex work_mutex_; -}; - -#else - -struct threadpool { - explicit - threadpool(std::string const& name, size_t number_threads = 0, thread_priority priority = thread_priority::normal) - {} - - void shutdown() {} - void join() {} - size_t size() const { - return 1; - } - bool empty() const { - return false; - } + size_t num_threads_; + ::asio::thread_pool pool_; }; -#endif // ! defined(__EMSCRIPTEN__) - } // namespace kth -#endif - +#endif // KTH_INFRASTRUCTURE_THREADPOOL_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/work.hpp b/src/infrastructure/include/kth/infrastructure/utility/work.hpp index 51fc765b..9a3e06b8 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/work.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/work.hpp @@ -13,40 +13,36 @@ #include #include #include -#include +#include #include #include #include namespace kth { -#define ORDERED "ordered" -#define UNORDERED "unordered" -#define CONCURRENT "concurrent" -#define SEQUENCE "sequence" - -/// This class is thread safe. -/// boost asio class wrapper to enable work heap management. -class KI_API work - : noncopyable -{ +/// This class is thread safe. +/// Executor-based work dispatcher for async operations. +class KI_API work : noncopyable { public: using ptr = std::shared_ptr; + using executor_type = ::asio::any_io_executor; + using strand_type = ::asio::strand; /// Create an instance. work(threadpool& pool, std::string const& name); /// Local execution for any operation, equivalent to std::bind. template - static void bound(Handler&& handler, Args&&... args) { + static + void bound(Handler&& handler, Args&&... args) { std::bind(std::forward(handler), std::forward(args)...)(); } /// Concurrent execution for any operation. template void concurrent(Handler&& handler, Args&&... args) { - // Service post ensures the job does not execute in the current thread. - ::asio::post(service_, std::bind(std::forward(handler), std::forward(args)...)); + // Post ensures the job does not execute in the current thread. + ::asio::post(executor_, std::bind(std::forward(handler), std::forward(args)...)); } /// Sequential execution for synchronous operations. @@ -60,11 +56,9 @@ class KI_API work /// Non-concurrent execution for synchronous operations. template void unordered(Handler&& handler, Args&&... args) { - // Use a strand wrapper to prevent concurrency and a service post + // Use a strand wrapper to prevent concurrency and a post // to deny ordering while ensuring execution on another thread. - // TODO: Review bind_executor vs deprecated wrap() for behavioral differences - // See: https://github.com/k-nuth/kth-mono/issues/76 - ::asio::post(service_, ::asio::bind_executor(strand_, std::bind(std::forward(handler), std::forward(args)...))); + ::asio::post(executor_, ::asio::bind_executor(strand_, std::bind(std::forward(handler), std::forward(args)...))); } /// Begin sequential execution for a set of asynchronous operations. @@ -81,34 +75,16 @@ class KI_API work sequence_.unlock(); } - ////size_t ordered_backlog(); - ////size_t unordered_backlog(); - ////size_t concurrent_backlog(); - ////size_t sequential_backlog(); - ////size_t combined_backlog(); + /// Get the executor. + [[nodiscard]] + executor_type get_executor() const { + return executor_; + } private: - ////template - ////auto inject(Handler&& handler, std::string const& context, - //// monitor::count_ptr counter) -> std::function - ////{ - //// auto label = name_ + "_" + context; - //// auto capture = std::make_shared(counter, std::move(label)); - //// return [=]() { capture->invoke(handler); }; - - //// //// TODO: use this to prevent handler copy into closure. - //// ////return std::bind(&monitor::invoke, capture, - //// //// std::forward(handler)); - ////} - - // These are thread safe. std::string const name_; - ////monitor::count_ptr ordered_; - ////monitor::count_ptr unordered_; - ////monitor::count_ptr concurrent_; - ////monitor::count_ptr sequential_; - asio::context& service_; - asio::context::strand strand_; + executor_type executor_; + strand_type strand_; sequencer sequence_; }; diff --git a/src/infrastructure/src/utility/deadline.cpp b/src/infrastructure/src/utility/deadline.cpp index 3b3e94ea..fab283ec 100644 --- a/src/infrastructure/src/utility/deadline.cpp +++ b/src/infrastructure/src/utility/deadline.cpp @@ -26,13 +26,13 @@ using std::placeholders::_1; #if ! defined(__EMSCRIPTEN__) deadline::deadline(threadpool& pool) : duration_(asio::seconds(0)) - , timer_(pool.service()) + , timer_(pool.get_executor()) /*, CONSTRUCT_TRACK(deadline)*/ {} deadline::deadline(threadpool& pool, asio::duration duration) : duration_(duration) - , timer_(pool.service()) + , timer_(pool.get_executor()) /*, CONSTRUCT_TRACK(deadline)*/ {} #endif diff --git a/src/infrastructure/src/utility/sequencer.cpp b/src/infrastructure/src/utility/sequencer.cpp index 92e94c57..aa406168 100644 --- a/src/infrastructure/src/utility/sequencer.cpp +++ b/src/infrastructure/src/utility/sequencer.cpp @@ -12,36 +12,15 @@ namespace kth { -sequencer::sequencer(asio::context& service) - : service_(service), executing_(false) +sequencer::sequencer(executor_type executor) + : executor_(std::move(executor)) + , executing_(false) {} sequencer::~sequencer() { KTH_ASSERT_MSG(actions_.empty(), "sequencer not cleared"); } -// void sequencer::lock(action&& handler) { -// auto post = false; - -// // Critical Section -// /////////////////////////////////////////////////////////////////////// -// mutex_.lock(); - -// if (executing_) { -// actions_.push(std::move(handler)); -// } else { -// post = true; -// executing_ = true; -// } - -// mutex_.unlock(); -// /////////////////////////////////////////////////////////////////////// - -// if (post) { -// ::asio::post(service_, std::move(handler)); -// } -// } - void sequencer::lock(action&& handler) { // Critical Section /////////////////////////////////////////////////////////////////////// @@ -56,7 +35,7 @@ void sequencer::lock(action&& handler) { } //unlock() /////////////////////////////////////////////////////////////////////// - ::asio::post(service_, std::move(handler)); + ::asio::post(executor_, std::move(handler)); } @@ -67,7 +46,6 @@ void sequencer::unlock() { // Critical Section /////////////////////////////////////////////////////////////////////// - // mutex_.lock(); { unique_lock locker(mutex_); @@ -85,7 +63,7 @@ void sequencer::unlock() { /////////////////////////////////////////////////////////////////////// if (handler) { - ::asio::post(service_, std::move(handler)); + ::asio::post(executor_, std::move(handler)); } } diff --git a/src/infrastructure/src/utility/socket.cpp b/src/infrastructure/src/utility/socket.cpp index 0959c550..44b4a8d1 100644 --- a/src/infrastructure/src/utility/socket.cpp +++ b/src/infrastructure/src/utility/socket.cpp @@ -15,7 +15,7 @@ namespace kth { socket::socket(threadpool& thread) : thread_(thread) - , socket_(thread_.service()) + , socket_(thread_.get_executor()) /*, CONSTRUCT_TRACK(socket) */ {} diff --git a/src/infrastructure/src/utility/threadpool.cpp b/src/infrastructure/src/utility/threadpool.cpp deleted file mode 100644 index 4030ee92..00000000 --- a/src/infrastructure/src/utility/threadpool.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -// #include -#include - -#include -#include -#include - -namespace kth { - -threadpool::threadpool(std::string const& name, size_t number_threads, thread_priority priority) - : name_(name) - , size_(0) -{ - // std::println("threadpool::threadpool() - name: {} - thread id: {}", name_, std::this_thread::get_id()); - spawn(number_threads, priority); -} - -threadpool::~threadpool() { - // std::println("threadpool::~threadpool() - name: {} - thread id: {}", name_, std::this_thread::get_id()); - shutdown(); - join(); -} - -// Should not be called during spawn. -bool threadpool::empty() const { - return size() != 0; -} - -// Should not be called during spawn. -size_t threadpool::size() const { - return size_.load(); -} - -// This is not thread safe. -void threadpool::spawn(size_t number_threads, thread_priority priority) { - // This allows the pool to be restarted. - service_.restart(); - // std::println("threadpool::spawn() - name: {} - thread id: {}", name_, std::this_thread::get_id()); - - for (size_t i = 0; i < number_threads; ++i) { - spawn_once(priority); - } -} - -void threadpool::spawn_once(thread_priority priority) { - // std::println("threadpool::spawn_once() - name: {} - thread id: {}", name_, std::this_thread::get_id()); - - /////////////////////////////////////////////////////////////////////////// - // Critical Section - work_mutex_.lock_upgrade(); - - // Work prevents the service from running out of work and terminating. - if ( ! work_) { - work_mutex_.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - work_ = std::make_shared(service_.get_executor()); - - work_mutex_.unlock_and_lock_upgrade(); - //----------------------------------------------------------------- - } - - work_mutex_.unlock_upgrade(); - /////////////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////////////// - // Critical Section - unique_lock lock(threads_mutex_); - - threads_.emplace_back([this, priority]() { - set_priority(priority); - // std::println("threadpool::spawn_once() *** BEFORE run() *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); - service_.run(); - // std::println("threadpool::spawn_once() *** AFTER run() *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); - }); - - ++size_; - /////////////////////////////////////////////////////////////////////////// -} - -void threadpool::abort() { - // std::println("threadpool::abort() *** BEFORE stop *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); - service_.stop(); - // std::println("threadpool::abort() *** AFTER stop *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); -} - -void threadpool::shutdown() { - abort(); - // std::println("threadpool::shutdown() *** BEFORE lock *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); - - // { - // /////////////////////////////////////////////////////////////////////////// - // // Critical Section - // unique_lock lock(work_mutex_); - - // work_.reset(); - // /////////////////////////////////////////////////////////////////////////// - // } - // std::println("threadpool::shutdown() *** AFTER lock *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); -} - -void threadpool::join() { - // std::println("threadpool::join() *** BEFORE lock *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); - - { - /////////////////////////////////////////////////////////////////////////// - // Critical Section - unique_lock lock(threads_mutex_); - - DEBUG_ONLY(auto const this_id = boost::this_thread::get_id();) - // auto const this_id = boost::this_thread::get_id(); - - // for (auto& thread: threads_) { - // KTH_ASSERT(this_id != thread.get_id()); - // KTH_ASSERT(thread.joinable()); - - // std::println("threadpool::join() - this_id != thread.get_id(): {}", this_id != thread.get_id()); - // std::println("threadpool::join() - thread.joinable(): {} - name: {} - thread id: {}", thread.joinable(), name_, thread.get_id()); - - // std::println("threadpool::join() *** BEFORE join *** - name: {} - thread id: {}", name_, thread.get_id()); - // thread.join(); - // std::println("threadpool::join() *** AFTER join *** - name: {} - thread id: {}", name_, thread.get_id()); - // } - - for (auto i = threads_.rbegin(); i != threads_.rend(); ++i ) { - auto& thread = *i; - - KTH_ASSERT(this_id != thread.get_id()); - KTH_ASSERT(thread.joinable()); - - // std::println("threadpool::join() - this_id != thread.get_id(): {}", this_id != thread.get_id()); - // std::println("threadpool::join() - thread.joinable(): {} - name: {} - thread id: {}", thread.joinable(), name_, thread.get_id()); - - // std::println("threadpool::join() *** BEFORE join *** - name: {} - thread id: {}", name_, thread.get_id()); - // thread.join(); - // std::println("threadpool::join() *** AFTER join *** - name: {} - thread id: {}", name_, thread.get_id()); - - // std::println("threadpool::join() *** BEFORE detach *** - name: {} - thread id: {}", name_, thread.get_id()); - thread.detach(); - // std::println("threadpool::join() *** AFTER detach *** - name: {} - thread id: {}", name_, thread.get_id()); - } - - threads_.clear(); - size_.store(0); - /////////////////////////////////////////////////////////////////////////// - } - - // std::println("threadpool::join() *** AFTER lock *** - name: {} - thread id: {}", name_, std::this_thread::get_id()); - -} - -asio::context& threadpool::service() { - return service_; -} - -const asio::context& threadpool::service() const { - return service_; -} - -} // namespace kth diff --git a/src/infrastructure/src/utility/work.cpp b/src/infrastructure/src/utility/work.cpp index da7034b3..43f70d41 100644 --- a/src/infrastructure/src/utility/work.cpp +++ b/src/infrastructure/src/utility/work.cpp @@ -6,47 +6,17 @@ #include #include +#include -#include #include namespace kth { work::work(threadpool& pool, std::string const& name) - : name_(name), - ////ordered_(std::make_shared(0)), - ////unordered_(std::make_shared(0)), - ////concurrent_(std::make_shared(0)), - ////sequential_(std::make_shared(0)), - service_(pool.service()), - strand_(service_), - sequence_(service_) -{ -} - -////size_t work::ordered_backlog() -////{ -//// return ordered_->load(); -////} -//// -////size_t work::unordered_backlog() -////{ -//// return unordered_->load(); -////} -//// -////size_t work::concurrent_backlog() -////{ -//// return concurrent_->load(); -////} -//// -////size_t work::sequential_backlog() -////{ -//// return sequential_->load(); -////} -//// -////size_t work::combined_backlog() -////{ -//// return ordered_backlog() + unordered_backlog() + concurrent_backlog(); -////} + : name_(name) + , executor_(pool.executor()) + , strand_(::asio::make_strand(executor_)) + , sequence_(executor_) +{} } // namespace kth diff --git a/src/infrastructure/test/utility/async_channel.cpp b/src/infrastructure/test/utility/async_channel.cpp new file mode 100644 index 00000000..71874677 --- /dev/null +++ b/src/infrastructure/test/utility/async_channel.cpp @@ -0,0 +1,399 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if defined(KTH_ASIO_STANDALONE) +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +using namespace kth; +using namespace std::chrono_literals; + +// Use the appropriate error_code type +#if defined(KTH_ASIO_STANDALONE) +using error_code_t = std::error_code; +#else +using error_code_t = boost::system::error_code; +#endif + +// ============================================================================= +// async_channel tests +// ============================================================================= + +TEST_CASE("async_channel basic send and receive", "[async_channel]") { + ::asio::io_context ctx; + + SECTION("send and receive single value") { + async_channel channel(ctx.get_executor(), 1); + + bool received = false; + int received_value = 0; + + // Producer coroutine + auto producer = [&]() -> ::asio::awaitable { + co_await channel.async_send(error_code_t{}, 42, ::asio::use_awaitable); + }; + + // Consumer coroutine + auto consumer = [&]() -> ::asio::awaitable { + auto [ec, value] = co_await channel.async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + received = true; + received_value = value; + } + }; + + ::asio::co_spawn(ctx, producer(), ::asio::detached); + ::asio::co_spawn(ctx, consumer(), ::asio::detached); + + ctx.run(); + + CHECK(received); + CHECK(received_value == 42); + } + + SECTION("send and receive string") { + async_channel channel(ctx.get_executor(), 1); + + std::string received_value; + + auto producer = [&]() -> ::asio::awaitable { + co_await channel.async_send(error_code_t{}, std::string("hello"), ::asio::use_awaitable); + }; + + auto consumer = [&]() -> ::asio::awaitable { + auto [ec, value] = co_await channel.async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + received_value = std::move(value); + } + }; + + ::asio::co_spawn(ctx, producer(), ::asio::detached); + ::asio::co_spawn(ctx, consumer(), ::asio::detached); + + ctx.run(); + + CHECK(received_value == "hello"); + } +} + +TEST_CASE("async_channel buffering", "[async_channel]") { + ::asio::io_context ctx; + + SECTION("buffered channel allows multiple sends before receive") { + async_channel channel(ctx.get_executor(), 3); + + std::vector received_values; + + auto producer = [&]() -> ::asio::awaitable { + co_await channel.async_send(error_code_t{}, 1, ::asio::use_awaitable); + co_await channel.async_send(error_code_t{}, 2, ::asio::use_awaitable); + co_await channel.async_send(error_code_t{}, 3, ::asio::use_awaitable); + }; + + auto consumer = [&]() -> ::asio::awaitable { + for (int i = 0; i < 3; ++i) { + auto [ec, value] = co_await channel.async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + received_values.push_back(value); + } + } + }; + + ::asio::co_spawn(ctx, producer(), ::asio::detached); + ::asio::co_spawn(ctx, consumer(), ::asio::detached); + + ctx.run(); + + REQUIRE(received_values.size() == 3); + CHECK(received_values[0] == 1); + CHECK(received_values[1] == 2); + CHECK(received_values[2] == 3); + } +} + +// ============================================================================= +// event_channel tests +// ============================================================================= + +TEST_CASE("event_channel signaling", "[async_channel][event]") { + ::asio::io_context ctx; + + SECTION("signal and wait") { + event_channel channel(ctx.get_executor(), 1); + + bool signaled = false; + + auto signaler = [&]() -> ::asio::awaitable { + co_await channel.async_send(error_code_t{}, ::asio::use_awaitable); + }; + + auto waiter = [&]() -> ::asio::awaitable { + auto [ec] = co_await channel.async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + signaled = true; + } + }; + + ::asio::co_spawn(ctx, signaler(), ::asio::detached); + ::asio::co_spawn(ctx, waiter(), ::asio::detached); + + ctx.run(); + + CHECK(signaled); + } +} + +// ============================================================================= +// multi_channel tests +// ============================================================================= + +TEST_CASE("multi_channel multiple values", "[async_channel][multi]") { + ::asio::io_context ctx; + + SECTION("send and receive tuple of values") { + multi_channel channel(ctx.get_executor(), 1); + + int received_int = 0; + std::string received_str; + + auto producer = [&]() -> ::asio::awaitable { + co_await channel.async_send(error_code_t{}, 42, std::string("test"), ::asio::use_awaitable); + }; + + auto consumer = [&]() -> ::asio::awaitable { + auto [ec, i, s] = co_await channel.async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + received_int = i; + received_str = std::move(s); + } + }; + + ::asio::co_spawn(ctx, producer(), ::asio::detached); + ::asio::co_spawn(ctx, consumer(), ::asio::detached); + + ctx.run(); + + CHECK(received_int == 42); + CHECK(received_str == "test"); + } +} + +// ============================================================================= +// async_channel with strand (NOT thread-safe, requires strand serialization) +// ============================================================================= +// +// IMPORTANT: async_channel is NOT thread-safe for concurrent access. +// Documentation: "Distinct objects: Safe. Shared objects: Unsafe." +// When using async_channel from multiple threads, ALL access must be +// serialized through a strand. +// +// ============================================================================= + +TEST_CASE("async_channel with strand serialization", "[async_channel][threadpool][strand]") { + SECTION("multiple producers with strand serialization") { + threadpool pool(4); + + // Create strand to serialize all channel access + ::asio::strand<::asio::any_io_executor> strand(pool.get_executor()); + + // Channel bound to strand - all operations will be serialized + async_channel channel(strand, 10); + + std::atomic sum{0}; + std::atomic count{0}; + std::atomic send_count{0}; + std::atomic consumer_done{false}; + + // 5 producer coroutines - spawned on strand for serialized access + for (int i = 1; i <= 5; ++i) { + ::asio::co_spawn(strand, + [&channel, &send_count, val = i]() -> ::asio::awaitable { + auto [ec] = co_await channel.async_send( + error_code_t{}, val, + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + ++send_count; + } + }, ::asio::detached); + } + + // Consumer coroutine - also on strand + ::asio::co_spawn(strand, + [&channel, &sum, &count, &consumer_done]() -> ::asio::awaitable { + for (int i = 0; i < 5; ++i) { + auto [ec, value] = co_await channel.async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + sum += value; + ++count; + } + } + consumer_done = true; + }, ::asio::detached); + + // Wait for consumer to complete + while (!consumer_done.load()) { + std::this_thread::sleep_for(1ms); + } + + pool.stop(); + pool.join(); + + INFO("send_count = " << send_count.load()); + INFO("count = " << count.load()); + INFO("sum = " << sum.load()); + + CHECK(send_count.load() == 5); + CHECK(count.load() == 5); + CHECK(sum.load() == 15); // 1+2+3+4+5 + } +} + +// ============================================================================= +// concurrent_channel (thread-safe, no strand needed) +// ============================================================================= +// +// concurrent_channel is thread-safe for concurrent access from multiple threads. +// Use this when producers/consumers run on different threads of the pool. +// +// ============================================================================= + +TEST_CASE("concurrent_channel without strand", "[concurrent_channel][threadpool]") { + SECTION("multiple producers from different threads - thread safe") { + threadpool pool(4); + + // concurrent_channel is thread-safe, no strand needed + concurrent_channel channel(pool.get_executor(), 10); + + std::atomic sum{0}; + std::atomic count{0}; + std::atomic send_count{0}; + std::atomic consumer_done{false}; + + // 5 producer coroutines - can run on any thread safely + for (int i = 1; i <= 5; ++i) { + ::asio::co_spawn(pool.get_executor(), + [&channel, &send_count, val = i]() -> ::asio::awaitable { + auto [ec] = co_await channel.async_send( + error_code_t{}, val, + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + ++send_count; + } + }, ::asio::detached); + } + + // Consumer coroutine - can run on any thread + ::asio::co_spawn(pool.get_executor(), + [&channel, &sum, &count, &consumer_done]() -> ::asio::awaitable { + for (int i = 0; i < 5; ++i) { + auto [ec, value] = co_await channel.async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + sum += value; + ++count; + } + } + consumer_done = true; + }, ::asio::detached); + + // Wait for consumer to complete + while (!consumer_done.load()) { + std::this_thread::sleep_for(1ms); + } + + pool.stop(); + pool.join(); + + INFO("send_count = " << send_count.load()); + INFO("count = " << count.load()); + INFO("sum = " << sum.load()); + + CHECK(send_count.load() == 5); + CHECK(count.load() == 5); + CHECK(sum.load() == 15); // 1+2+3+4+5 + } + + SECTION("high contention stress test") { + threadpool pool(8); + concurrent_channel channel(pool.get_executor(), 100); + + constexpr int num_producers = 20; + constexpr int items_per_producer = 10; + constexpr int total_items = num_producers * items_per_producer; + + std::atomic sum{0}; + std::atomic send_count{0}; + std::atomic receive_count{0}; + std::atomic done{false}; + + // Many producers sending concurrently + for (int p = 0; p < num_producers; ++p) { + ::asio::co_spawn(pool.get_executor(), + [&channel, &send_count, p]() -> ::asio::awaitable { + for (int i = 0; i < items_per_producer; ++i) { + int value = p * items_per_producer + i + 1; + auto [ec] = co_await channel.async_send( + error_code_t{}, value, + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + ++send_count; + } + } + }, ::asio::detached); + } + + // Single consumer receiving all items + ::asio::co_spawn(pool.get_executor(), + [&channel, &sum, &receive_count, &done]() -> ::asio::awaitable { + for (int i = 0; i < total_items; ++i) { + auto [ec, value] = co_await channel.async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + sum += value; + ++receive_count; + } + } + done = true; + }, ::asio::detached); + + // Wait for completion + while (!done.load()) { + std::this_thread::sleep_for(1ms); + } + + pool.stop(); + pool.join(); + + // Expected sum: 1+2+3+...+200 = 200*201/2 = 20100 + int expected_sum = total_items * (total_items + 1) / 2; + + INFO("send_count = " << send_count.load()); + INFO("receive_count = " << receive_count.load()); + INFO("sum = " << sum.load()); + INFO("expected_sum = " << expected_sum); + + CHECK(send_count.load() == total_items); + CHECK(receive_count.load() == total_items); + CHECK(sum.load() == expected_sum); + } +} diff --git a/src/infrastructure/test/utility/awaitable_helpers.cpp b/src/infrastructure/test/utility/awaitable_helpers.cpp new file mode 100644 index 00000000..07711316 --- /dev/null +++ b/src/infrastructure/test/utility/awaitable_helpers.cpp @@ -0,0 +1,228 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include + +#if defined(KTH_ASIO_STANDALONE) +#include +#include +#else +#include +#include +#endif + +using namespace kth; +using namespace std::chrono_literals; + +// Helper to run a coroutine and get the result +template +T run_coro(::asio::io_context& ctx, awaitable coro) { + T result{}; + ::asio::co_spawn(ctx, std::move(coro), [&](std::exception_ptr ep, T value) { + if (ep) std::rethrow_exception(ep); + result = std::move(value); + }); + ctx.run(); + return result; +} + +// Overload for void +inline void run_coro(::asio::io_context& ctx, awaitable coro) { + ::asio::co_spawn(ctx, std::move(coro), [](std::exception_ptr ep) { + if (ep) std::rethrow_exception(ep); + }); + ctx.run(); +} + +// ============================================================================= +// delay() tests +// ============================================================================= + +TEST_CASE("delay basic functionality", "[awaitable_helpers][delay]") { + ::asio::io_context ctx; + + SECTION("delay completes after specified duration") { + auto start = std::chrono::steady_clock::now(); + + run_coro(ctx, delay(50ms)); + + auto elapsed = std::chrono::steady_clock::now() - start; + auto ms = std::chrono::duration_cast(elapsed).count(); + + // Should take at least 50ms (allow some tolerance) + CHECK(ms >= 45); + CHECK(ms < 200); // But not too long + } + + SECTION("delay with different duration types") { + auto start = std::chrono::steady_clock::now(); + + run_coro(ctx, delay(std::chrono::microseconds(50000))); // 50ms + + auto elapsed = std::chrono::steady_clock::now() - start; + auto ms = std::chrono::duration_cast(elapsed).count(); + + CHECK(ms >= 45); + } +} + +// ============================================================================= +// with_timeout() tests +// ============================================================================= + +namespace { + +awaitable slow_operation(std::chrono::milliseconds duration) { + co_await delay(duration); + co_return 42; +} + +awaitable fast_operation() { + co_await delay(10ms); + co_return 123; +} + +} // anonymous namespace + +TEST_CASE("with_timeout success case", "[awaitable_helpers][timeout]") { + ::asio::io_context ctx; + + SECTION("operation completes before timeout") { + auto test_coro = []() -> awaitable> { + co_return co_await with_timeout(fast_operation(), 500ms); + }; + + auto result = run_coro(ctx, test_coro()); + + REQUIRE(result.has_value()); + CHECK(result.value() == 123); + } +} + +TEST_CASE("with_timeout timeout case", "[awaitable_helpers][timeout]") { + ::asio::io_context ctx; + + SECTION("operation times out") { + auto test_coro = []() -> awaitable> { + co_return co_await with_timeout(slow_operation(500ms), 50ms); + }; + + auto result = run_coro(ctx, test_coro()); + + REQUIRE_FALSE(result.has_value()); + CHECK(result.error() == make_error_code(std::errc::timed_out)); + } +} + +// ============================================================================= +// with_timeout with expected return type +// ============================================================================= + +namespace { + +enum class custom_error { + none = 0, + timeout, + other +}; + +std::error_code make_error_code(custom_error e) { + static struct : std::error_category { + char const* name() const noexcept override { return "custom"; } + std::string message(int ev) const override { + switch (static_cast(ev)) { + case custom_error::none: return "none"; + case custom_error::timeout: return "timeout"; + case custom_error::other: return "other"; + default: return "unknown"; + } + } + } category; + return {static_cast(e), category}; +} + +awaitable> expected_operation(bool succeed) { + co_await delay(10ms); + if (succeed) { + co_return "success"; + } + co_return std::unexpected(custom_error::other); +} + +} // anonymous namespace + +TEST_CASE("with_timeout with expected return", "[awaitable_helpers][timeout][expected]") { + ::asio::io_context ctx; + + SECTION("successful operation with custom timeout error") { + auto test_coro = []() -> awaitable> { + co_return co_await with_timeout( + expected_operation(true), + 500ms, + custom_error::timeout + ); + }; + + auto result = run_coro(ctx, test_coro()); + + REQUIRE(result.has_value()); + CHECK(result.value() == "success"); + } + + SECTION("operation error propagates") { + auto test_coro = []() -> awaitable> { + co_return co_await with_timeout( + expected_operation(false), + 500ms, + custom_error::timeout + ); + }; + + auto result = run_coro(ctx, test_coro()); + + REQUIRE_FALSE(result.has_value()); + CHECK(result.error() == custom_error::other); + } +} + +// ============================================================================= +// post_to() tests +// ============================================================================= + +TEST_CASE("post_to switches executor", "[awaitable_helpers][post_to]") { + threadpool pool1(2); + threadpool pool2(2); + + ::asio::io_context ctx; + + SECTION("can post to different executor") { + std::atomic executed_on_pool{false}; + + auto test_coro = [&]() -> awaitable { + co_await post_to(pool1.get_executor()); + executed_on_pool = true; + }; + + ::asio::co_spawn(ctx, test_coro(), ::asio::detached); + ctx.run(); + + // Give pool time to execute + std::this_thread::sleep_for(50ms); + + pool1.stop(); + pool1.join(); + pool2.stop(); + pool2.join(); + + CHECK(executed_on_pool.load()); + } +} diff --git a/src/infrastructure/test/utility/threadpool.cpp b/src/infrastructure/test/utility/threadpool.cpp new file mode 100644 index 00000000..0c14e786 --- /dev/null +++ b/src/infrastructure/test/utility/threadpool.cpp @@ -0,0 +1,227 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include + +#include + +using namespace kth; + +TEST_CASE("threadpool construction", "[threadpool]") { + SECTION("default construction uses hardware concurrency") { + threadpool pool; + CHECK(pool.size() == std::thread::hardware_concurrency()); + } + + SECTION("explicit thread count") { + threadpool pool(4); + CHECK(pool.size() == 4); + } + + SECTION("zero threads defaults to hardware concurrency") { + threadpool pool(0); + CHECK(pool.size() == std::thread::hardware_concurrency()); + } +} + +TEST_CASE("threadpool executor", "[threadpool]") { + threadpool pool(2); + + SECTION("get_executor returns valid executor") { + auto exec = pool.get_executor(); + // Should be able to post work to it + std::atomic executed{false}; + ::asio::post(exec, [&]() { + executed = true; + }); + + // Give it time to execute + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + pool.stop(); + pool.join(); + + CHECK(executed.load()); + } + + SECTION("executor returns valid executor") { + auto exec = pool.executor(); + std::atomic executed{false}; + ::asio::post(exec, [&]() { + executed = true; + }); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + pool.stop(); + pool.join(); + + CHECK(executed.load()); + } +} + +TEST_CASE("threadpool work execution", "[threadpool]") { + threadpool pool(4); + + SECTION("single task execution") { + std::atomic counter{0}; + + ::asio::post(pool.get_executor(), [&]() { + counter++; + }); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + pool.stop(); + pool.join(); + + CHECK(counter.load() == 1); + } + + SECTION("multiple tasks execution") { + std::atomic counter{0}; + int const num_tasks = 100; + + for (int i = 0; i < num_tasks; ++i) { + ::asio::post(pool.get_executor(), [&]() { + counter++; + }); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + pool.stop(); + pool.join(); + + CHECK(counter.load() == num_tasks); + } + + SECTION("concurrent execution") { + std::atomic max_concurrent{0}; + std::atomic current{0}; + int const num_tasks = 10; + + for (int i = 0; i < num_tasks; ++i) { + ::asio::post(pool.get_executor(), [&]() { + int val = ++current; + // Update max if this is highest concurrent + int expected = max_concurrent.load(); + while (val > expected && !max_concurrent.compare_exchange_weak(expected, val)) {} + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + --current; + }); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + pool.stop(); + pool.join(); + + // With 4 threads, we should see some concurrency + CHECK(max_concurrent.load() > 1); + } +} + +TEST_CASE("threadpool stop and join", "[threadpool]") { + using namespace std::chrono_literals; + + SECTION("join without stop waits for all pending work") { + threadpool pool(2); + std::atomic completed{0}; + + // Post multiple tasks + for (int i = 0; i < 5; ++i) { + ::asio::post(pool.get_executor(), [&]() { + std::this_thread::sleep_for(10ms); + ++completed; + }); + } + + // join() without stop() waits for ALL work to complete + pool.join(); + + CHECK(completed.load() == 5); + } + + SECTION("stop cancels pending work that has not started") { + threadpool pool(1); // Single thread to control execution order + std::atomic first_started{false}; + std::atomic first_done{false}; + std::atomic second_done{false}; + + // First task - takes a while + ::asio::post(pool.get_executor(), [&]() { + first_started = true; + std::this_thread::sleep_for(50ms); + first_done = true; + }); + + // Second task - should be cancelled by stop() + ::asio::post(pool.get_executor(), [&]() { + second_done = true; + }); + + // Wait for first task to start (so second is queued but not running) + while (!first_started.load()) { + std::this_thread::sleep_for(1ms); + } + + // stop() cancels pending work (second task) + pool.stop(); + pool.join(); + + CHECK(first_done.load()); // First task completed (was already running) + CHECK_FALSE(second_done.load()); // Second task was cancelled (was pending) + } + + SECTION("stop does not block - requires separate join") { + threadpool pool(2); + std::atomic work_running{false}; + std::atomic work_done{false}; + + ::asio::post(pool.get_executor(), [&]() { + work_running = true; + std::this_thread::sleep_for(100ms); + work_done = true; + }); + + // Wait for work to start + while (!work_running.load()) { + std::this_thread::sleep_for(1ms); + } + + // stop() should return immediately, not wait for work + pool.stop(); + + // Work should still be running (stop doesn't join) + CHECK_FALSE(work_done.load()); + + // Now join to wait for completion + pool.join(); + CHECK(work_done.load()); + } + + SECTION("join after stop waits for running work to complete") { + threadpool pool(2); + std::atomic work_started{false}; + std::atomic work_done{false}; + + ::asio::post(pool.get_executor(), [&]() { + work_started = true; + std::this_thread::sleep_for(50ms); + work_done = true; + }); + + // Wait for work to start before stopping + while (!work_started.load()) { + std::this_thread::sleep_for(1ms); + } + + pool.stop(); + pool.join(); + + // Work that was already running should complete + CHECK(work_done.load()); + } +} diff --git a/src/network/src/acceptor.cpp b/src/network/src/acceptor.cpp index 627eecf3..5b0a376d 100644 --- a/src/network/src/acceptor.cpp +++ b/src/network/src/acceptor.cpp @@ -26,7 +26,7 @@ acceptor::acceptor(threadpool& pool, settings const& settings) , pool_(pool) , settings_(settings) , dispatch_(pool, NAME) - , acceptor_(pool_.service()) + , acceptor_(pool_.get_executor()) , CONSTRUCT_TRACK(acceptor) {} acceptor::~acceptor() { diff --git a/src/network/src/connector.cpp b/src/network/src/connector.cpp index f44c202e..a2b2b742 100644 --- a/src/network/src/connector.cpp +++ b/src/network/src/connector.cpp @@ -26,7 +26,7 @@ connector::connector(threadpool& pool, settings const& settings) , pool_(pool) , settings_(settings) , dispatch_(pool, NAME) - , resolver_(pool.service()) + , resolver_(pool.get_executor()) , CONSTRUCT_TRACK(connector) {} diff --git a/src/network/src/p2p.cpp b/src/network/src/p2p.cpp index 0dc6fc94..beb3f0eb 100644 --- a/src/network/src/p2p.cpp +++ b/src/network/src/p2p.cpp @@ -57,7 +57,7 @@ p2p::p2p(settings const& settings) , pending_connect_(nominal_connecting(settings_)) , pending_handshake_(nominal_connected(settings_)) , pending_close_(nominal_connected(settings_)) - , threadpool_("network") + , threadpool_(thread_default(settings_.threads)) , stop_subscriber_(std::make_shared(threadpool_, NAME "_stop_sub")) , channel_subscriber_(std::make_shared(threadpool_, NAME "_sub")) {} @@ -76,8 +76,7 @@ void p2p::start(result_handler handler) { return; } - threadpool_.join(); - threadpool_.spawn(thread_default(settings_.threads), thread_priority::normal); + // threadpool is already running from construction stopped_ = false; stop_subscriber_->start(); @@ -258,7 +257,7 @@ bool p2p::stop() { pending_close_.stop(error::service_stopped); // Signal threadpool to stop accepting work now that subscribers are clear. - threadpool_.shutdown(); + threadpool_.stop(); return result; } From 7919fe37e1360ae9a54e8d9cf3a00da3a3cf35fb Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 13:59:44 +0100 Subject: [PATCH 03/14] feature: add peer_session with connection helpers (Phase 2-3) (#142) Add coroutine-based peer_session class that replaces proxy/channel: - peer_session: modern async peer connection handler using C++20 coroutines - Concurrent read/write/timer loops using asio::awaitable operators - Message framing with Bitcoin protocol validation (magic, checksum, payload size) - Inactivity and expiration timers for connection lifecycle Add connection helper functions (Phase 3): - async_connect(): DNS resolution + TCP connect with timeout - async_accept(): accept incoming connections - async_listen(): create listening acceptor on port Includes comprehensive unit tests (31 test cases): - Construction, properties, lifecycle management - Message send/receive with protocol validation - Timer behavior (inactivity, expiration) - Bidirectional communication - Connection helpers (listen, accept, connect, timeout) --- src/network/CMakeLists.txt | 3 + src/network/include/kth/network.hpp | 1 + .../include/kth/network/peer_session.hpp | 260 +++++ src/network/src/peer_session.cpp | 466 +++++++++ src/network/test/peer_session.cpp | 970 ++++++++++++++++++ 5 files changed, 1700 insertions(+) create mode 100644 src/network/include/kth/network/peer_session.hpp create mode 100644 src/network/src/peer_session.cpp create mode 100644 src/network/test/peer_session.cpp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 2e12a6f1..534f11b7 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -93,6 +93,7 @@ endif() set(kth_headers include/kth/network/acceptor.hpp include/kth/network/define.hpp + include/kth/network/peer_session.hpp include/kth/network/proxy.hpp include/kth/network/channel.hpp include/kth/network/hosts.hpp @@ -142,6 +143,7 @@ set(kth_sources src/hosts.cpp src/message_subscriber.cpp src/p2p.cpp + src/peer_session.cpp src/proxy.cpp src/settings.cpp ) @@ -180,6 +182,7 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") add_executable(kth_network_test test/p2p.cpp + test/peer_session.cpp ) target_include_directories(kth_network_test PUBLIC $) diff --git a/src/network/include/kth/network.hpp b/src/network/include/kth/network.hpp index ef3d1882..9c50080c 100644 --- a/src/network/include/kth/network.hpp +++ b/src/network/include/kth/network.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/src/network/include/kth/network/peer_session.hpp b/src/network/include/kth/network/peer_session.hpp new file mode 100644 index 00000000..6868a135 --- /dev/null +++ b/src/network/include/kth/network/peer_session.hpp @@ -0,0 +1,260 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NETWORK_PEER_SESSION_HPP +#define KTH_NETWORK_PEER_SESSION_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// Asio includes for coroutines +#include +#include +#include +#include +#include +#include + +namespace kth::network { + +// ============================================================================= +// peer_session: Modern coroutine-based peer connection handler +// ============================================================================= +// +// Replaces the legacy proxy/channel classes with a simpler coroutine-based +// implementation. All I/O operations are serialized through a strand, +// eliminating the need for explicit mutexes. +// +// Usage: +// auto session = std::make_shared(std::move(socket), settings); +// co_spawn(executor, session->run(), detached); +// +// // Send a message +// co_await session->send(version_message); +// +// // Receive messages via channel +// auto [ec, msg] = co_await session->messages().async_receive(...); +// +// ============================================================================= + +/// Represents a raw message received from a peer +struct raw_message { + domain::message::heading heading; + data_chunk payload; +}; + +/// Modern coroutine-based peer session, replaces proxy/channel +class KN_API peer_session : public std::enable_shared_from_this { +public: + using ptr = std::shared_ptr; + using executor_type = ::asio::any_io_executor; + using strand_type = ::asio::strand; + using socket_type = ::asio::ip::tcp::socket; + + // Channel for outbound messages (serialized bytes ready to send) + using outbound_channel = concurrent_channel; + + // Channel for inbound messages (raw message with heading + payload) + using inbound_channel = concurrent_channel; + + /// Construct a peer session from an established socket + peer_session(socket_type socket, settings const& settings); + + /// Destructor - ensures clean shutdown + ~peer_session(); + + // ------------------------------------------------------------------------- + // Lifecycle + // ------------------------------------------------------------------------- + + /// Main coroutine - runs read/write/timer loops concurrently + /// Returns when the session is stopped or an error occurs + [[nodiscard]] + ::asio::awaitable run(); + + /// Stop the session gracefully + void stop(code const& ec = error::channel_stopped); + + /// Check if the session is stopped + [[nodiscard]] + bool stopped() const; + + // ------------------------------------------------------------------------- + // Messaging + // ------------------------------------------------------------------------- + + /// Send a message to the peer (coroutine version) + template + ::asio::awaitable send(Message const& message) { + if (stopped()) { + co_return error::channel_stopped; + } + + auto data = domain::message::serialize(version_.load(), message, protocol_magic_); + auto [ec] = co_await outbound_.async_send( + std::error_code{}, + std::move(data), + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + co_return error::channel_stopped; + } + co_return error::success; + } + + /// Send raw bytes to the peer (coroutine version) + ::asio::awaitable send_raw(data_chunk data); + + /// Get the inbound message channel for receiving messages + [[nodiscard]] + inbound_channel& messages(); + + // ------------------------------------------------------------------------- + // Properties + // ------------------------------------------------------------------------- + + /// Get the authority (address:port) of the remote peer + [[nodiscard]] + infrastructure::config::authority const& authority() const; + + /// Get/set the negotiated protocol version + [[nodiscard]] + uint32_t negotiated_version() const; + void set_negotiated_version(uint32_t value); + + /// Get/set the peer's version message + [[nodiscard]] + domain::message::version::const_ptr peer_version() const; + void set_peer_version(domain::message::version::const_ptr value); + + /// Get/set the nonce for this connection + [[nodiscard]] + uint64_t nonce() const; + void set_nonce(uint64_t value); + + /// Get/set whether to notify on new inventory + [[nodiscard]] + bool notify() const; + void set_notify(bool value); + +private: + // ------------------------------------------------------------------------- + // Internal coroutines + // ------------------------------------------------------------------------- + + /// Read loop - reads messages from socket and dispatches to inbound channel + ::asio::awaitable read_loop(); + + /// Write loop - processes outbound channel and writes to socket + ::asio::awaitable write_loop(); + + /// Inactivity timer - stops session if no messages received + ::asio::awaitable inactivity_timer(); + + /// Expiration timer - stops session after lifetime expires + ::asio::awaitable expiration_timer(); + + /// Read a complete message (heading + payload) + ::asio::awaitable> read_message(); + + /// Signal activity (resets inactivity timer) + void signal_activity(); + + // ------------------------------------------------------------------------- + // Data members + // ------------------------------------------------------------------------- + + // Socket and strand (all I/O serialized through strand) + socket_type socket_; + strand_type strand_; + + // Channels for message passing + outbound_channel outbound_; + inbound_channel inbound_; + + // Timers + ::asio::steady_timer inactivity_timer_; + ::asio::steady_timer expiration_timer_; + std::atomic activity_signaled_{false}; + + // State + std::atomic stopped_{false}; + infrastructure::config::authority authority_; + + // Protocol settings + uint32_t const protocol_magic_; + size_t const maximum_payload_; + bool const validate_checksum_; + std::chrono::seconds const inactivity_timeout_; + std::chrono::seconds const expiration_timeout_; + + // Negotiated values (atomic for thread-safe access) + std::atomic version_; + std::atomic nonce_{0}; + std::atomic notify_{true}; + kth::atomic peer_version_; + + // Buffers (only accessed from read_loop, no synchronization needed) + data_chunk heading_buffer_; +}; + +// ============================================================================= +// Connection helpers - replace connector/acceptor classes +// ============================================================================= + +/// Connect to a peer by hostname and port +/// Resolves DNS and connects with timeout +/// @param executor The executor to use for async operations +/// @param hostname The hostname or IP address to connect to +/// @param port The port number +/// @param settings Network settings for the connection +/// @param timeout Connection timeout +/// @return awaitable that yields a peer_session::ptr or error code +[[nodiscard]] +::asio::awaitable> async_connect( + ::asio::any_io_executor executor, + std::string const& hostname, + uint16_t port, + settings const& settings, + std::chrono::seconds timeout); + +/// Connect to a peer by authority (address:port) +[[nodiscard]] +::asio::awaitable> async_connect( + ::asio::any_io_executor executor, + infrastructure::config::authority const& authority, + settings const& settings, + std::chrono::seconds timeout); + +/// Accept a single incoming connection +/// @param acceptor An already-listening TCP acceptor +/// @param settings Network settings for the connection +/// @return awaitable that yields a peer_session::ptr or error code +[[nodiscard]] +::asio::awaitable> async_accept( + ::asio::ip::tcp::acceptor& acceptor, + settings const& settings); + +/// Start listening on a port and return an acceptor +/// @param executor The executor to use +/// @param port The port to listen on +/// @return awaitable that yields an acceptor or error code +[[nodiscard]] +::asio::awaitable> async_listen( + ::asio::any_io_executor executor, + uint16_t port); + +} // namespace kth::network + +#endif // KTH_NETWORK_PEER_SESSION_HPP diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp new file mode 100644 index 00000000..1d07e9d4 --- /dev/null +++ b/src/network/src/peer_session.cpp @@ -0,0 +1,466 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include +#include + +#include + +namespace kth::network { + +using namespace std::chrono_literals; +using namespace ::asio::experimental::awaitable_operators; +using namespace kth::domain::message; + +namespace { + +// Helper to extract authority from socket +infrastructure::config::authority extract_authority(::asio::ip::tcp::socket const& socket) { + boost_code ec; + auto const endpoint = socket.remote_endpoint(ec); + if (ec) { + return {}; + } + return infrastructure::config::authority(endpoint); +} + +} // anonymous namespace + +// ============================================================================= +// Construction / Destruction +// ============================================================================= + +peer_session::peer_session(socket_type socket, settings const& settings) + : socket_(std::move(socket)) + , strand_(socket_.get_executor()) + , outbound_(strand_, 100) // Buffer up to 100 outbound messages + , inbound_(strand_, 100) // Buffer up to 100 inbound messages + , inactivity_timer_(strand_) + , expiration_timer_(strand_) + , authority_(extract_authority(socket_)) + , protocol_magic_(settings.identifier) + , maximum_payload_(heading::maximum_payload_size( + settings.protocol_maximum, + settings.identifier, + settings.inbound_port == 48333)) + , validate_checksum_(settings.validate_checksum) + , inactivity_timeout_(std::chrono::minutes(settings.channel_inactivity_minutes)) + , expiration_timeout_(std::chrono::minutes(settings.channel_expiration_minutes)) + , version_(settings.protocol_maximum) + , heading_buffer_(heading::maximum_size()) +{} + +peer_session::~peer_session() { + stop(error::channel_stopped); +} + +// ============================================================================= +// Lifecycle +// ============================================================================= + +::asio::awaitable peer_session::run() { + if (stopped()) { + co_return error::channel_stopped; + } + + stopped_ = false; + + try { + // Run all loops concurrently - when any completes/fails, all stop + co_await ( + read_loop() || + write_loop() || + inactivity_timer() || + expiration_timer() + ); + } catch (std::exception const& e) { + spdlog::debug("[peer_session] Exception in run loop [{}]: {}", authority(), e.what()); + } + + stop(error::channel_stopped); + co_return error::channel_stopped; +} + +void peer_session::stop(code const& ec) { + if (stopped_.exchange(true)) { + return; // Already stopped + } + + spdlog::debug("[peer_session] Stopping session [{}]: {}", authority(), ec.message()); + + // Cancel timers (standalone Asio cancel() takes no args) + inactivity_timer_.cancel(); + expiration_timer_.cancel(); + + // Close channels + outbound_.close(); + inbound_.close(); + + // Shutdown socket + boost_code ignore; + socket_.shutdown(::asio::ip::tcp::socket::shutdown_both, ignore); + socket_.cancel(); +} + +bool peer_session::stopped() const { + return stopped_.load(); +} + +// ============================================================================= +// Messaging +// ============================================================================= + +::asio::awaitable peer_session::send_raw(data_chunk data) { + if (stopped()) { + co_return error::channel_stopped; + } + + auto [ec] = co_await outbound_.async_send( + std::error_code{}, + std::move(data), + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + co_return error::channel_stopped; + } + co_return error::success; +} + +peer_session::inbound_channel& peer_session::messages() { + return inbound_; +} + +// ============================================================================= +// Properties +// ============================================================================= + +infrastructure::config::authority const& peer_session::authority() const { + return authority_; +} + +uint32_t peer_session::negotiated_version() const { + return version_.load(); +} + +void peer_session::set_negotiated_version(uint32_t value) { + version_.store(value); +} + +domain::message::version::const_ptr peer_session::peer_version() const { + return peer_version_.load(); +} + +void peer_session::set_peer_version(domain::message::version::const_ptr value) { + peer_version_.store(std::move(value)); +} + +uint64_t peer_session::nonce() const { + return nonce_.load(); +} + +void peer_session::set_nonce(uint64_t value) { + nonce_.store(value); +} + +bool peer_session::notify() const { + return notify_.load(); +} + +void peer_session::set_notify(bool value) { + notify_.store(value); +} + +// ============================================================================= +// Internal Coroutines +// ============================================================================= + +::asio::awaitable peer_session::read_loop() { + while (!stopped()) { + auto result = co_await read_message(); + + if (!result) { + spdlog::debug("[peer_session] Read error [{}]: {}", authority(), result.error().message()); + stop(result.error()); + co_return; + } + + // Signal activity to reset inactivity timer + signal_activity(); + + // Send message to inbound channel + auto [ec] = co_await inbound_.async_send( + std::error_code{}, + std::move(*result), + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + spdlog::debug("[peer_session] Failed to enqueue message [{}]", authority()); + stop(error::channel_stopped); + co_return; + } + } +} + +::asio::awaitable peer_session::write_loop() { + while (!stopped()) { + auto [ec, data] = co_await outbound_.async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + // Channel closed or error + co_return; + } + + // Write to socket + auto [write_ec, bytes_written] = co_await ::asio::async_write( + socket_, + ::asio::buffer(data), + ::asio::as_tuple(::asio::use_awaitable)); + + if (write_ec) { + spdlog::debug("[peer_session] Write error [{}]: {}", + authority(), write_ec.message()); + stop(error::boost_to_error_code(write_ec)); + co_return; + } + + spdlog::trace("[peer_session] Sent {} bytes to [{}]", bytes_written, authority()); + } +} + +::asio::awaitable peer_session::inactivity_timer() { + while (!stopped()) { + activity_signaled_ = false; + inactivity_timer_.expires_after(inactivity_timeout_); + + auto [ec] = co_await inactivity_timer_.async_wait( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec == ::asio::error::operation_aborted) { + // Timer was cancelled (reset or stop) + continue; + } + + if (ec) { + co_return; + } + + // Timer expired - check if there was activity + if (!activity_signaled_.load()) { + spdlog::debug("[peer_session] Inactivity timeout [{}]", authority()); + stop(error::channel_timeout); + co_return; + } + } +} + +::asio::awaitable peer_session::expiration_timer() { + expiration_timer_.expires_after(expiration_timeout_); + + auto [ec] = co_await expiration_timer_.async_wait( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec == ::asio::error::operation_aborted) { + co_return; + } + + spdlog::debug("[peer_session] Session expired [{}]", authority()); + stop(error::channel_timeout); +} + +::asio::awaitable> peer_session::read_message() { + // Read heading (24 bytes) + auto [head_ec, head_bytes] = co_await ::asio::async_read( + socket_, + ::asio::buffer(heading_buffer_), + ::asio::as_tuple(::asio::use_awaitable)); + + if (head_ec) { + co_return std::unexpected(error::boost_to_error_code(head_ec)); + } + + // Parse heading + byte_reader reader(heading_buffer_); + auto head_result = heading::from_data(reader, 0); + + if (!head_result) { + spdlog::warn("[peer_session] Failed to parse heading from [{}]", authority()); + co_return std::unexpected(error::bad_stream); + } + + auto const& head = *head_result; + + if (!head.is_valid()) { + spdlog::warn("[peer_session] Invalid heading from [{}]", authority()); + co_return std::unexpected(error::bad_stream); + } + + if (head.magic() != protocol_magic_) { + spdlog::debug("[peer_session] Invalid magic ({}) from [{}]", head.magic(), authority()); + co_return std::unexpected(error::bad_stream); + } + + if (head.payload_size() > maximum_payload_) { + spdlog::debug("[peer_session] Oversized payload ({} bytes) from [{}]", + head.payload_size(), authority()); + co_return std::unexpected(error::bad_stream); + } + + // Read payload + data_chunk payload(head.payload_size()); + + if (head.payload_size() > 0) { + auto [payload_ec, payload_bytes] = co_await ::asio::async_read( + socket_, + ::asio::buffer(payload), + ::asio::as_tuple(::asio::use_awaitable)); + + if (payload_ec) { + co_return std::unexpected(error::boost_to_error_code(payload_ec)); + } + } + + // Validate checksum if required + if (validate_checksum_ && head.checksum() != bitcoin_checksum(payload)) { + spdlog::warn("[peer_session] Invalid checksum for {} from [{}]", + head.command(), authority()); + co_return std::unexpected(error::bad_stream); + } + + spdlog::debug("[peer_session] Received {} from [{}] ({} bytes)", + head.command(), authority(), head.payload_size()); + + co_return raw_message{head, std::move(payload)}; +} + +void peer_session::signal_activity() { + activity_signaled_ = true; + // Cancel and restart the inactivity timer + inactivity_timer_.cancel(); +} + +// ============================================================================= +// Connection helpers - replace connector/acceptor classes +// ============================================================================= + +::asio::awaitable> async_connect( + ::asio::any_io_executor executor, + std::string const& hostname, + uint16_t port, + settings const& settings, + std::chrono::seconds timeout) +{ + using namespace ::asio::experimental::awaitable_operators; + + // Create resolver + ::asio::ip::tcp::resolver resolver(executor); + + // Resolve hostname + auto [resolve_ec, endpoints] = co_await resolver.async_resolve( + hostname, + std::to_string(port), + ::asio::as_tuple(::asio::use_awaitable)); + + if (resolve_ec) { + spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); + co_return std::unexpected(error::resolve_failed); + } + + // Create socket and timer for timeout + ::asio::ip::tcp::socket socket(executor); + ::asio::steady_timer timer(executor); + timer.expires_after(timeout); + + // Race: connect vs timeout + auto result = co_await ( + ::asio::async_connect(socket, endpoints, ::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + // Timeout won + spdlog::debug("[async_connect] Connection to {}:{} timed out", hostname, port); + co_return std::unexpected(error::channel_timeout); + } + + auto [connect_ec, endpoint] = std::get<0>(result); + if (connect_ec) { + spdlog::debug("[async_connect] Failed to connect to {}:{}: {}", + hostname, port, connect_ec.message()); + co_return std::unexpected(error::boost_to_error_code(connect_ec)); + } + + spdlog::debug("[async_connect] Connected to {}:{}", hostname, port); + co_return std::make_shared(std::move(socket), settings); +} + +::asio::awaitable> async_connect( + ::asio::any_io_executor executor, + infrastructure::config::authority const& authority, + settings const& settings, + std::chrono::seconds timeout) +{ + co_return co_await async_connect( + executor, + authority.to_hostname(), + authority.port(), + settings, + timeout); +} + +::asio::awaitable> async_accept( + ::asio::ip::tcp::acceptor& acceptor, + settings const& settings) +{ + auto [ec, socket] = co_await acceptor.async_accept( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + if (ec == ::asio::error::operation_aborted) { + co_return std::unexpected(error::service_stopped); + } + spdlog::debug("[async_accept] Accept failed: {}", ec.message()); + co_return std::unexpected(error::boost_to_error_code(ec)); + } + + boost_code peer_ec; + auto const endpoint = socket.remote_endpoint(peer_ec); + if (!peer_ec) { + spdlog::debug("[async_accept] Accepted connection from {}:{}", + endpoint.address().to_string(), endpoint.port()); + } + + co_return std::make_shared(std::move(socket), settings); +} + +::asio::awaitable> async_listen( + ::asio::any_io_executor executor, + uint16_t port) +{ + try { + ::asio::ip::tcp::acceptor acceptor(executor); + + // Open, set options, bind, listen + acceptor.open(::asio::ip::tcp::v6()); + acceptor.set_option(::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor.set_option(::asio::ip::v6_only(false)); // Accept both IPv4 and IPv6 + + acceptor.bind(::asio::ip::tcp::endpoint(::asio::ip::tcp::v6(), port)); + acceptor.listen(::asio::socket_base::max_listen_connections); + + spdlog::info("[async_listen] Listening on port {}", port); + co_return std::move(acceptor); + + } catch (std::system_error const& e) { + spdlog::error("[async_listen] Failed to listen on port {}: {}", port, e.what()); + co_return std::unexpected(error::boost_to_error_code(e.code())); + } +} + +} // namespace kth::network diff --git a/src/network/test/peer_session.cpp b/src/network/test/peer_session.cpp new file mode 100644 index 00000000..7d37af21 --- /dev/null +++ b/src/network/test/peer_session.cpp @@ -0,0 +1,970 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace kth; +using namespace kth::network; +using namespace std::chrono_literals; + +// ============================================================================= +// Test helpers +// ============================================================================= + +// Create a connected socket pair for testing (client, server) +// Uses a background thread to handle the accept +std::pair<::asio::ip::tcp::socket, ::asio::ip::tcp::socket> +make_connected_sockets(::asio::io_context& ctx) { + ::asio::ip::tcp::acceptor acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = acceptor.local_endpoint().port(); + + ::asio::ip::tcp::socket client(ctx); + ::asio::ip::tcp::socket server(ctx); + + // Run accept in a thread + std::thread accept_thread([&]() { + server = acceptor.accept(); + }); + + // Connect from main thread + client.connect({::asio::ip::address_v4::loopback(), port}); + + accept_thread.join(); + + return {std::move(client), std::move(server)}; +} + +// Helper to run context with timeout and stop condition +template +void run_until(::asio::io_context& ctx, Predicate pred, std::chrono::milliseconds timeout = 1000ms) { + auto deadline = std::chrono::steady_clock::now() + timeout; + while (!pred() && std::chrono::steady_clock::now() < deadline) { + ctx.run_for(10ms); + } +} + +// Create default settings for testing +network::settings make_test_settings() { + network::settings settings; + settings.identifier = 0xe8f3e1e3; // BCH testnet magic + settings.protocol_maximum = 70015; + settings.validate_checksum = true; + settings.channel_inactivity_minutes = 1; + settings.channel_expiration_minutes = 5; + settings.inbound_port = 18333; + return settings; +} + +// Build a valid Bitcoin protocol message +data_chunk build_message(std::string const& command, data_chunk const& payload, uint32_t magic) { + data_chunk message; + message.reserve(24 + payload.size()); + + // Magic (4 bytes, little-endian) + auto const magic_le = to_little_endian(magic); + message.insert(message.end(), magic_le.begin(), magic_le.end()); + + // Command (12 bytes, null-padded) + std::array cmd{}; + std::copy_n(command.begin(), std::min(command.size(), size_t{12}), cmd.begin()); + message.insert(message.end(), cmd.begin(), cmd.end()); + + // Payload size (4 bytes, little-endian) + auto const size_le = to_little_endian(static_cast(payload.size())); + message.insert(message.end(), size_le.begin(), size_le.end()); + + // Checksum (4 bytes) - first 4 bytes of double SHA256 + auto const hash = bitcoin_hash(payload); + message.insert(message.end(), hash.begin(), hash.begin() + 4); + + // Payload + message.insert(message.end(), payload.begin(), payload.end()); + + return message; +} + +// ============================================================================= +// Construction and Properties Tests +// ============================================================================= + +TEST_CASE("peer_session construction", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + REQUIRE(!session->stopped()); + REQUIRE(session->negotiated_version() == settings.protocol_maximum); +} + +TEST_CASE("peer_session authority is populated", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + auto const& auth = session->authority(); + REQUIRE(auth.port() != 0); +} + +TEST_CASE("peer_session negotiated version get set", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + REQUIRE(session->negotiated_version() == 70015); + + session->set_negotiated_version(70001); + REQUIRE(session->negotiated_version() == 70001); + + session->set_negotiated_version(31402); + REQUIRE(session->negotiated_version() == 31402); +} + +TEST_CASE("peer_session nonce get set", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + REQUIRE(session->nonce() == 0); + + session->set_nonce(0x123456789ABCDEF0); + REQUIRE(session->nonce() == 0x123456789ABCDEF0); + + session->set_nonce(42); + REQUIRE(session->nonce() == 42); +} + +TEST_CASE("peer_session notify get set", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + REQUIRE(session->notify() == true); + + session->set_notify(false); + REQUIRE(session->notify() == false); + + session->set_notify(true); + REQUIRE(session->notify() == true); +} + +TEST_CASE("peer_session peer version get set", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + REQUIRE(session->peer_version() == nullptr); + + auto version = std::make_shared(); + version->set_value(70015); + version->set_services(1); + version->set_user_agent("/Knuth:0.1.0/"); + + session->set_peer_version(version); + + auto retrieved = session->peer_version(); + REQUIRE(retrieved != nullptr); + REQUIRE(retrieved->value() == 70015); + REQUIRE(retrieved->user_agent() == "/Knuth:0.1.0/"); +} + +// ============================================================================= +// Lifecycle Tests +// ============================================================================= + +TEST_CASE("peer_session stop", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + REQUIRE(!session->stopped()); + session->stop(); + REQUIRE(session->stopped()); +} + +TEST_CASE("peer_session stop is idempotent", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + session->stop(); + REQUIRE(session->stopped()); + + // Multiple stops should not crash + session->stop(); + session->stop(error::channel_timeout); + REQUIRE(session->stopped()); +} + +TEST_CASE("peer_session stop with error code", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + session->stop(error::channel_timeout); + REQUIRE(session->stopped()); +} + +TEST_CASE("peer_session run returns when stopped", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + std::atomic run_completed{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await session->run(); + run_completed = true; + }, ::asio::detached); + + // Run a bit + ctx.run_for(20ms); + REQUIRE(!run_completed); + + // Stop and let it complete + session->stop(); + run_until(ctx, [&]{ return run_completed.load(); }); + + REQUIRE(run_completed); +} + +// ============================================================================= +// Message Send Tests +// ============================================================================= + +TEST_CASE("peer_session send raw data", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + // Prepare to receive on client + std::array recv_buffer; + std::atomic bytes_received{0}; + + client.async_read_some(::asio::buffer(recv_buffer), + [&](auto ec, size_t n) { + if (!ec) bytes_received = n; + }); + + // Start session and send data + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + data_chunk pong_payload; + auto pong_msg = build_message("pong", pong_payload, settings.identifier); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await session->send_raw(pong_msg); + }, ::asio::detached); + + run_until(ctx, [&]{ return bytes_received.load() > 0; }); + + session->stop(); + ctx.run_for(10ms); + + REQUIRE(bytes_received == pong_msg.size()); +} + +TEST_CASE("peer_session send typed message ping", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + // Prepare to receive on client + std::array recv_buffer; + std::atomic bytes_received{0}; + + client.async_read_some(::asio::buffer(recv_buffer), + [&](auto ec, size_t n) { + if (!ec) bytes_received = n; + }); + + // Start session + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + // Send typed ping message + domain::message::ping ping_msg(12345); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await session->send(ping_msg); + }, ::asio::detached); + + run_until(ctx, [&]{ return bytes_received.load() > 0; }); + + session->stop(); + ctx.run_for(10ms); + + // Should have received header (24 bytes) + payload (8 bytes for nonce) + REQUIRE(bytes_received == 32); +} + +TEST_CASE("peer_session send returns error when stopped", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + session->stop(); + + std::atomic done{false}; + code send_result = error::success; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + send_result = co_await session->send(domain::message::ping(0)); + done = true; + }, ::asio::detached); + + run_until(ctx, [&]{ return done.load(); }); + + REQUIRE(send_result == error::channel_stopped); +} + +// ============================================================================= +// Message Receive Tests +// ============================================================================= + +TEST_CASE("peer_session receive message", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + std::atomic message_received{false}; + std::string received_command; + + // Start the session and receiver + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + auto [ec, msg] = co_await session->messages().async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (!ec) { + message_received = true; + received_command = msg.heading.command(); + } + }, ::asio::detached); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + // Give session time to start + ctx.run_for(10ms); + + // Send a ping message from client + data_chunk ping_payload; + auto ping_msg = build_message("ping", ping_payload, settings.identifier); + + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(ping_msg), write_ec); + REQUIRE(!write_ec); + + run_until(ctx, [&]{ return message_received.load(); }); + + session->stop(); + ctx.run_for(10ms); + + REQUIRE(message_received); + REQUIRE(received_command == "ping"); +} + +TEST_CASE("peer_session receive multiple messages", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + std::atomic messages_received{0}; + + // Start receiver + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + while (!session->stopped() && messages_received < 5) { + auto [ec, msg] = co_await session->messages().async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + ++messages_received; + } else { + break; + } + } + }, ::asio::detached); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + // Give session time to start + ctx.run_for(10ms); + + // Send multiple messages + for (int i = 0; i < 5; ++i) { + auto msg = build_message("ping", {}, settings.identifier); + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(msg), write_ec); + REQUIRE(!write_ec); + } + + run_until(ctx, [&]{ return messages_received.load() >= 5; }); + + session->stop(); + ctx.run_for(10ms); + + REQUIRE(messages_received == 5); +} + +TEST_CASE("peer_session receive message with payload", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + std::atomic message_received{false}; + data_chunk received_payload; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + auto [ec, msg] = co_await session->messages().async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + message_received = true; + received_payload = std::move(msg.payload); + } + }, ::asio::detached); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + ctx.run_for(10ms); + + // Send ping with nonce payload (8 bytes) + data_chunk ping_payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + auto msg = build_message("ping", ping_payload, settings.identifier); + + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(msg), write_ec); + REQUIRE(!write_ec); + + run_until(ctx, [&]{ return message_received.load(); }); + + session->stop(); + ctx.run_for(10ms); + + REQUIRE(message_received); + REQUIRE(received_payload.size() == 8); + REQUIRE(received_payload == ping_payload); +} + +// ============================================================================= +// Protocol Validation Tests +// ============================================================================= + +TEST_CASE("peer_session invalid magic rejected", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + ctx.run_for(10ms); + + // Send message with wrong magic + uint32_t wrong_magic = 0xdeadbeef; + data_chunk bad_msg = build_message("ping", {}, wrong_magic); + + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(bad_msg), write_ec); + REQUIRE(!write_ec); + + run_until(ctx, [&]{ return session->stopped(); }); + + REQUIRE(session->stopped()); +} + +TEST_CASE("peer_session invalid checksum rejected", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + ctx.run_for(10ms); + + // Build message then corrupt checksum + auto msg = build_message("ping", {}, settings.identifier); + msg[20] ^= 0xFF; + + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(msg), write_ec); + REQUIRE(!write_ec); + + run_until(ctx, [&]{ return session->stopped(); }); + + REQUIRE(session->stopped()); +} + +TEST_CASE("peer_session oversized payload rejected", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + ctx.run_for(10ms); + + // Build header claiming huge payload + data_chunk bad_header; + + auto magic_le = to_little_endian(settings.identifier); + bad_header.insert(bad_header.end(), magic_le.begin(), magic_le.end()); + + std::array cmd{}; + std::copy_n("ping", 4, cmd.begin()); + bad_header.insert(bad_header.end(), cmd.begin(), cmd.end()); + + // 100 MB - way too big + auto size_le = to_little_endian(uint32_t{100 * 1024 * 1024}); + bad_header.insert(bad_header.end(), size_le.begin(), size_le.end()); + + bad_header.insert(bad_header.end(), {0, 0, 0, 0}); + + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(bad_header), write_ec); + REQUIRE(!write_ec); + + run_until(ctx, [&]{ return session->stopped(); }); + + REQUIRE(session->stopped()); +} + +// ============================================================================= +// Connection Close Tests +// ============================================================================= + +TEST_CASE("peer_session connection closed by peer", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + std::atomic run_completed{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await session->run(); + run_completed = true; + }, ::asio::detached); + + ctx.run_for(50ms); + + // Close client connection + client.close(); + + run_until(ctx, [&]{ return session->stopped(); }); + + REQUIRE(session->stopped()); +} + +TEST_CASE("peer_session graceful shutdown", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + std::atomic run_completed{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await session->run(); + run_completed = true; + }, ::asio::detached); + + ctx.run_for(50ms); + + session->stop(error::service_stopped); + + run_until(ctx, [&]{ return run_completed.load(); }); + + REQUIRE(session->stopped()); + REQUIRE(run_completed); +} + +// ============================================================================= +// Concurrent Access Tests (thread safety) +// ============================================================================= + +TEST_CASE("peer_session concurrent property access", "[peer_session][concurrent]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + // Multiple threads accessing properties concurrently + std::vector threads; + + for (int i = 0; i < 4; ++i) { + threads.emplace_back([&, i]() { + for (int j = 0; j < 100; ++j) { + session->set_negotiated_version(70000 + i); + [[maybe_unused]] auto v = session->negotiated_version(); + + session->set_nonce(i * 1000 + j); + [[maybe_unused]] auto n = session->nonce(); + + session->set_notify(j % 2 == 0); + [[maybe_unused]] auto notify = session->notify(); + } + }); + } + + for (auto& t : threads) { + t.join(); + } + + // No crashes = success + REQUIRE(true); +} + +// ============================================================================= +// Timer Tests +// ============================================================================= + +TEST_CASE("peer_session inactivity timeout", "[peer_session][timer]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + // Very short inactivity timeout for testing (0 minutes = immediate) + settings.channel_inactivity_minutes = 0; + + auto [client, server] = make_connected_sockets(ctx); + auto session = std::make_shared(std::move(server), settings); + + std::atomic run_completed{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await session->run(); + run_completed = true; + }, ::asio::detached); + + // With 0 minutes timeout, session should stop due to inactivity + run_until(ctx, [&]{ return session->stopped(); }, 2000ms); + + REQUIRE(session->stopped()); +} + +// ============================================================================= +// Bidirectional Communication Tests +// ============================================================================= + +TEST_CASE("peer_session bidirectional communication", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + auto session = std::make_shared(std::move(server), settings); + + std::atomic messages_received{0}; + std::atomic messages_sent{0}; + + // Receiver coroutine - receives pings and sends pongs back + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + while (!session->stopped() && messages_received < 3) { + auto [ec, msg] = co_await session->messages().async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + ++messages_received; + // Echo back a pong for each ping + co_await session->send(domain::message::pong(0)); + ++messages_sent; + } else { + break; + } + } + }, ::asio::detached); + + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + + // Give session time to start + ctx.run_for(10ms); + + // Client receives pongs + std::array recv_buffer; + std::atomic pongs_received{0}; + + std::function read_handler; + read_handler = [&](std::error_code ec, size_t n) { + if (!ec && n >= 24) { + ++pongs_received; + if (pongs_received < 3) { + client.async_read_some(::asio::buffer(recv_buffer), read_handler); + } + } + }; + client.async_read_some(::asio::buffer(recv_buffer), read_handler); + + // Send 3 pings from client + for (int i = 0; i < 3; ++i) { + auto ping_msg = build_message("ping", {}, settings.identifier); + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(ping_msg), write_ec); + REQUIRE(!write_ec); + } + + run_until(ctx, [&]{ return messages_received.load() >= 3 && pongs_received.load() >= 1; }, 2000ms); + + session->stop(); + ctx.run_for(10ms); + + REQUIRE(messages_received == 3); + REQUIRE(messages_sent == 3); + REQUIRE(pongs_received >= 1); // At least some pongs received +} + +// ============================================================================= +// Destructor Test +// ============================================================================= + +TEST_CASE("peer_session destructor stops session", "[peer_session]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + auto [client, server] = make_connected_sockets(ctx); + + { + auto session = std::make_shared(std::move(server), settings); + ::asio::co_spawn(ctx, session->run(), ::asio::detached); + ctx.run_for(50ms); + // session destructor called here when shared_ptr ref count goes to 0 + } + + // Context should be able to complete without hanging + ctx.run_for(50ms); + REQUIRE(true); +} + +// ============================================================================= +// async_listen / async_accept Tests +// ============================================================================= + +TEST_CASE("async_listen creates acceptor on port", "[peer_session][helpers]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + + std::atomic done{false}; + std::expected<::asio::ip::tcp::acceptor, code> result = std::unexpected(error::unknown); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await async_listen(ctx.get_executor(), 0); // Port 0 = random available port + done = true; + }, ::asio::detached); + + run_until(ctx, [&]{ return done.load(); }); + + REQUIRE(result.has_value()); + REQUIRE(result->is_open()); + + auto port = result->local_endpoint().port(); + REQUIRE(port != 0); + + result->close(); +} + +TEST_CASE("async_accept accepts connection", "[peer_session][helpers]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + + // Create acceptor directly (simpler than async_listen for this test) + ::asio::ip::tcp::acceptor acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = acceptor.local_endpoint().port(); + REQUIRE(port != 0); + + std::atomic accept_done{false}; + std::expected accept_result = std::unexpected(error::unknown); + + // Connect from a separate thread (so it doesn't block io_context) + std::thread client_thread([port]() { + ::asio::io_context client_ctx; + ::asio::ip::tcp::socket client(client_ctx); + std::error_code ec; + client.connect({::asio::ip::address_v4::loopback(), port}, ec); + // Keep socket alive briefly + std::this_thread::sleep_for(100ms); + }); + + // Accept in coroutine + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + accept_result = co_await async_accept(acceptor, settings); + accept_done = true; + }, ::asio::detached); + + run_until(ctx, [&]{ return accept_done.load(); }, 2000ms); + client_thread.join(); + + REQUIRE(accept_result.has_value()); + REQUIRE(accept_result.value() != nullptr); + REQUIRE(!accept_result.value()->stopped()); + + accept_result.value()->stop(); + acceptor.close(); +} + +TEST_CASE("async_accept returns error when acceptor closed", "[peer_session][helpers]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + // Create and close acceptor + auto listen_result = ::asio::ip::tcp::acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = listen_result.local_endpoint().port(); + + // Start accept then close + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await async_accept(listen_result, settings); + done = true; + }, ::asio::detached); + + ctx.run_for(10ms); + listen_result.close(); + + run_until(ctx, [&]{ return done.load(); }); + + REQUIRE(!result.has_value()); + REQUIRE(result.error() == error::service_stopped); +} + +// ============================================================================= +// async_connect Tests (these are [integration] since they need network) +// ============================================================================= + +TEST_CASE("async_connect to local acceptor", "[peer_session][helpers]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + + // Setup: create a listening socket + ::asio::ip::tcp::acceptor acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = acceptor.local_endpoint().port(); + + std::atomic connect_done{false}; + std::expected connect_result = std::unexpected(error::unknown); + + // Accept in background thread + std::thread accept_thread([&]() { + acceptor.accept(); + }); + + // Connect + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + connect_result = co_await async_connect( + ctx.get_executor(), + "127.0.0.1", + port, + settings, + std::chrono::seconds{5}); + connect_done = true; + }, ::asio::detached); + + run_until(ctx, [&]{ return connect_done.load(); }, 5000ms); + accept_thread.join(); + + REQUIRE(connect_result.has_value()); + REQUIRE(connect_result.value() != nullptr); + REQUIRE(!connect_result.value()->stopped()); + + connect_result.value()->stop(); + acceptor.close(); +} + +TEST_CASE("async_connect timeout", "[peer_session][helpers]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + // Connect to a non-routable IP with short timeout + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await async_connect( + ctx.get_executor(), + "10.255.255.1", // Non-routable, will timeout + 12345, + settings, + std::chrono::seconds{1}); // Short timeout + done = true; + }, ::asio::detached); + + run_until(ctx, [&]{ return done.load(); }, 3000ms); + + REQUIRE(!result.has_value()); + REQUIRE(result.error() == error::channel_timeout); +} + +TEST_CASE("async_connect with authority", "[peer_session][helpers]") { + ::asio::io_context ctx; + auto settings = make_test_settings(); + + // Setup: create a listening socket + ::asio::ip::tcp::acceptor acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = acceptor.local_endpoint().port(); + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + std::thread accept_thread([&]() { + acceptor.accept(); + }); + + // Create authority + infrastructure::config::authority auth("127.0.0.1", port); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await async_connect( + ctx.get_executor(), + auth, + settings, + std::chrono::seconds{5}); + done = true; + }, ::asio::detached); + + run_until(ctx, [&]{ return done.load(); }, 5000ms); + accept_thread.join(); + + REQUIRE(result.has_value()); + REQUIRE(result.value() != nullptr); + + result.value()->stop(); + acceptor.close(); +} From 20151742cc1c7526248493f61175501f7aecc5fe Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 14:02:21 +0100 Subject: [PATCH 04/14] feat(network): add peer_manager for unified peer collection management (#144) Add peer_manager class that replaces the legacy pending/ pending collections with a single unified collection. Key features: - All operations are coroutines (asio::awaitable) - Uses asio::strand for serialization (no mutex needed) - add/remove/find operations with nonce or authority lookup - broadcast template for sending messages to all peers - for_each handler for iterating over active peers - Capacity limiting with max_connections parameter Includes comprehensive unit tests for all functionality. --- src/network/CMakeLists.txt | 3 + src/network/include/kth/network.hpp | 1 + .../include/kth/network/peer_manager.hpp | 160 +++++ src/network/src/peer_manager.cpp | 206 ++++++ src/network/test/peer_manager.cpp | 620 ++++++++++++++++++ 5 files changed, 990 insertions(+) create mode 100644 src/network/include/kth/network/peer_manager.hpp create mode 100644 src/network/src/peer_manager.cpp create mode 100644 src/network/test/peer_manager.cpp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 534f11b7..2ff30359 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -94,6 +94,7 @@ set(kth_headers include/kth/network/acceptor.hpp include/kth/network/define.hpp include/kth/network/peer_session.hpp + include/kth/network/peer_manager.hpp include/kth/network/proxy.hpp include/kth/network/channel.hpp include/kth/network/hosts.hpp @@ -144,6 +145,7 @@ set(kth_sources src/message_subscriber.cpp src/p2p.cpp src/peer_session.cpp + src/peer_manager.cpp src/proxy.cpp src/settings.cpp ) @@ -182,6 +184,7 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") add_executable(kth_network_test test/p2p.cpp + test/peer_manager.cpp test/peer_session.cpp ) diff --git a/src/network/include/kth/network.hpp b/src/network/include/kth/network.hpp index 9c50080c..3cc8f306 100644 --- a/src/network/include/kth/network.hpp +++ b/src/network/include/kth/network.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/src/network/include/kth/network/peer_manager.hpp b/src/network/include/kth/network/peer_manager.hpp new file mode 100644 index 00000000..ad31815a --- /dev/null +++ b/src/network/include/kth/network/peer_manager.hpp @@ -0,0 +1,160 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NETWORK_PEER_MANAGER_HPP +#define KTH_NETWORK_PEER_MANAGER_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace kth::network { + +// ============================================================================= +// peer_manager: Modern coroutine-based peer connection manager +// ============================================================================= +// +// Replaces the legacy pending/pending collections in p2p +// with a single unified collection. All operations are serialized through +// a strand, eliminating the need for explicit mutexes. +// +// Usage: +// peer_manager manager(executor, settings); +// +// // Add a connected peer +// co_await manager.add(session); +// +// // Broadcast to all peers +// co_await manager.broadcast(message); +// +// // Remove a peer +// co_await manager.remove(session); +// +// ============================================================================= + +class KN_API peer_manager { +public: + using ptr = std::shared_ptr; + using peer_handler = std::function; + + /// Construct a peer manager + /// @param executor The executor for async operations + /// @param max_connections Maximum number of connections (0 = unlimited) + explicit peer_manager(::asio::any_io_executor executor, size_t max_connections = 0); + + /// Destructor - stops all peers + ~peer_manager(); + + // ------------------------------------------------------------------------- + // Peer Management + // ------------------------------------------------------------------------- + + /// Add a peer to the manager + /// @param peer The peer session to add + /// @return success if added, error if duplicate or at capacity + ::asio::awaitable add(peer_session::ptr peer); + + /// Remove a peer from the manager + /// @param peer The peer session to remove + ::asio::awaitable remove(peer_session::ptr peer); + + /// Remove a peer by nonce + /// @param nonce The nonce of the peer to remove + ::asio::awaitable remove_by_nonce(uint64_t nonce); + + /// Check if a peer with the given nonce exists + /// @param nonce The nonce to check + /// @return true if exists + ::asio::awaitable exists_by_nonce(uint64_t nonce) const; + + /// Check if a peer with the given authority exists + /// @param authority The authority (ip:port) to check + /// @return true if exists + ::asio::awaitable exists_by_authority(infrastructure::config::authority const& authority) const; + + /// Find a peer by nonce + /// @param nonce The nonce to find + /// @return The peer session or nullptr if not found + ::asio::awaitable find_by_nonce(uint64_t nonce) const; + + /// Get all connected peers (snapshot) + /// @return Vector of peer sessions + ::asio::awaitable> all() const; + + /// Get the number of connected peers + /// @return Count of peers + ::asio::awaitable count() const; + + // ------------------------------------------------------------------------- + // Synchronous accessors (for compatibility, use with care) + // ------------------------------------------------------------------------- + + /// Get the number of connected peers (non-awaitable) + /// Thread-safe but may be slightly stale + size_t count_snapshot() const; + + // ------------------------------------------------------------------------- + // Broadcasting + // ------------------------------------------------------------------------- + + /// Broadcast a message to all connected peers + /// @param message The message to broadcast + /// @return Number of peers the message was sent to + template + ::asio::awaitable broadcast(Message const& message) { + auto peers = co_await all(); + size_t sent = 0; + + for (auto const& peer : peers) { + if (!peer->stopped()) { + auto ec = co_await peer->send(message); + if (!ec) { + ++sent; + } + } + } + + co_return sent; + } + + /// Execute a handler for each peer + /// @param handler The handler to execute + ::asio::awaitable for_each(peer_handler handler); + + // ------------------------------------------------------------------------- + // Lifecycle + // ------------------------------------------------------------------------- + + /// Stop all peers and clear the collection + void stop_all(); + + /// Check if the manager is stopped + bool stopped() const; + +private: + // Strand for serializing access to peers_ + ::asio::strand<::asio::any_io_executor> strand_; + + // Peers indexed by nonce + std::unordered_map peers_; + + // Configuration + size_t const max_connections_; + std::atomic stopped_{false}; + std::atomic count_{0}; // For snapshot access +}; + +} // namespace kth::network + +#endif // KTH_NETWORK_PEER_MANAGER_HPP diff --git a/src/network/src/peer_manager.cpp b/src/network/src/peer_manager.cpp new file mode 100644 index 00000000..35c1cbca --- /dev/null +++ b/src/network/src/peer_manager.cpp @@ -0,0 +1,206 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include +#include +#include + +namespace kth::network { + +// ============================================================================= +// Construction / Destruction +// ============================================================================= + +peer_manager::peer_manager(::asio::any_io_executor executor, size_t max_connections) + : strand_(::asio::make_strand(executor)) + , max_connections_(max_connections) +{} + +peer_manager::~peer_manager() { + // Direct cleanup in destructor - no async dispatch needed + // since no other operations can be in flight during destruction + stopped_.store(true); + for (auto& [nonce, peer] : peers_) { + peer->stop(); + } + peers_.clear(); + count_.store(0); +} + +// ============================================================================= +// Peer Management +// ============================================================================= + +::asio::awaitable peer_manager::add(peer_session::ptr peer) { + if (stopped()) { + co_return error::service_stopped; + } + + if (!peer) { + co_return error::operation_failed; + } + + auto nonce = peer->nonce(); + if (nonce == 0) { + // Generate a temporary nonce based on address hash if not set + // This allows adding peers before handshake completes + auto const& auth = peer->authority(); + nonce = std::hash{}(auth.to_string()); + } + + // Execute on strand + auto result = co_await ::asio::co_spawn(strand_, [this, peer, nonce]() -> ::asio::awaitable { + // Check capacity + if (max_connections_ > 0 && peers_.size() >= max_connections_) { + co_return error::channel_stopped; // At capacity + } + + // Check for duplicate + if (peers_.find(nonce) != peers_.end()) { + co_return error::address_in_use; // Duplicate nonce + } + + // Check for duplicate authority + auto const& new_auth = peer->authority(); + for (auto const& [existing_nonce, existing_peer] : peers_) { + if (existing_peer->authority() == new_auth) { + co_return error::address_in_use; // Duplicate authority + } + } + + // Add peer + peers_.emplace(nonce, peer); + count_.store(peers_.size()); + + spdlog::debug("[peer_manager] Added peer [{}], total: {}", + peer->authority(), peers_.size()); + + co_return error::success; + }, ::asio::use_awaitable); + + co_return result; +} + +::asio::awaitable peer_manager::remove(peer_session::ptr peer) { + if (!peer) { + co_return; + } + + auto nonce = peer->nonce(); + if (nonce == 0) { + auto const& auth = peer->authority(); + nonce = std::hash{}(auth.to_string()); + } + + co_await remove_by_nonce(nonce); +} + +::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { + co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { + auto it = peers_.find(nonce); + if (it != peers_.end()) { + spdlog::debug("[peer_manager] Removed peer [{}], remaining: {}", + it->second->authority(), peers_.size() - 1); + peers_.erase(it); + count_.store(peers_.size()); + } + co_return; + }, ::asio::use_awaitable); +} + +::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { + co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { + co_return peers_.find(nonce) != peers_.end(); + }, ::asio::use_awaitable); +} + +::asio::awaitable peer_manager::exists_by_authority( + infrastructure::config::authority const& authority) const +{ + co_return co_await ::asio::co_spawn(strand_, [this, &authority]() -> ::asio::awaitable { + for (auto const& [nonce, peer] : peers_) { + if (peer->authority() == authority) { + co_return true; + } + } + co_return false; + }, ::asio::use_awaitable); +} + +::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) const { + co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { + auto it = peers_.find(nonce); + if (it != peers_.end()) { + co_return it->second; + } + co_return nullptr; + }, ::asio::use_awaitable); +} + +::asio::awaitable> peer_manager::all() const { + co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable> { + std::vector result; + result.reserve(peers_.size()); + for (auto const& [nonce, peer] : peers_) { + result.push_back(peer); + } + co_return result; + }, ::asio::use_awaitable); +} + +::asio::awaitable peer_manager::count() const { + co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable { + co_return peers_.size(); + }, ::asio::use_awaitable); +} + +size_t peer_manager::count_snapshot() const { + return count_.load(); +} + +// ============================================================================= +// Broadcasting +// ============================================================================= + +::asio::awaitable peer_manager::for_each(peer_handler handler) { + auto peers = co_await all(); + for (auto const& peer : peers) { + if (!peer->stopped()) { + handler(peer); + } + } +} + +// ============================================================================= +// Lifecycle +// ============================================================================= + +void peer_manager::stop_all() { + if (stopped_.exchange(true)) { + return; // Already stopped + } + + spdlog::debug("[peer_manager] Stopping all peers"); + + // Post to strand to safely iterate and clean up + // Note: Callers should run the io_context to ensure completion + ::asio::post(strand_, [this]() { + for (auto& [nonce, peer] : peers_) { + peer->stop(); + } + peers_.clear(); + count_.store(0); + }); +} + +bool peer_manager::stopped() const { + return stopped_.load(); +} + +} // namespace kth::network diff --git a/src/network/test/peer_manager.cpp b/src/network/test/peer_manager.cpp new file mode 100644 index 00000000..8055c5e5 --- /dev/null +++ b/src/network/test/peer_manager.cpp @@ -0,0 +1,620 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace kth; +using namespace kth::network; +using namespace std::chrono_literals; + +// ============================================================================= +// Test helpers +// ============================================================================= + +// Create a connected socket pair for testing (client, server) +std::pair<::asio::ip::tcp::socket, ::asio::ip::tcp::socket> +make_connected_sockets_pm(::asio::io_context& ctx) { + ::asio::ip::tcp::acceptor acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = acceptor.local_endpoint().port(); + + ::asio::ip::tcp::socket client(ctx); + ::asio::ip::tcp::socket server(ctx); + + std::thread accept_thread([&]() { + server = acceptor.accept(); + }); + + client.connect({::asio::ip::address_v4::loopback(), port}); + + accept_thread.join(); + + return {std::move(client), std::move(server)}; +} + +// Helper to run context with timeout and stop condition +template +void run_until_pm(::asio::io_context& ctx, Predicate pred, std::chrono::milliseconds timeout = 1000ms) { + auto deadline = std::chrono::steady_clock::now() + timeout; + while (!pred() && std::chrono::steady_clock::now() < deadline) { + ctx.run_for(10ms); + } +} + +// Create default settings for testing +network::settings make_test_settings_pm() { + network::settings settings; + settings.identifier = 0xe8f3e1e3; // BCH testnet magic + settings.protocol_maximum = 70015; + settings.validate_checksum = true; + settings.channel_inactivity_minutes = 1; + settings.channel_expiration_minutes = 5; + settings.inbound_port = 18333; + return settings; +} + +// Create a peer_session for testing +peer_session::ptr make_test_peer(::asio::io_context& ctx) { + auto settings = make_test_settings_pm(); + auto [client, server] = make_connected_sockets_pm(ctx); + return std::make_shared(std::move(server), settings); +} + +// ============================================================================= +// Construction Tests +// ============================================================================= + +TEST_CASE("peer_manager construction", "[peer_manager]") { + ::asio::io_context ctx; + + peer_manager manager(ctx.get_executor(), 100); + + REQUIRE(!manager.stopped()); + REQUIRE(manager.count_snapshot() == 0); +} + +TEST_CASE("peer_manager construction unlimited", "[peer_manager]") { + ::asio::io_context ctx; + + peer_manager manager(ctx.get_executor(), 0); // Unlimited + + REQUIRE(!manager.stopped()); +} + +// ============================================================================= +// Add/Remove Tests +// ============================================================================= + +TEST_CASE("peer_manager add peer", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + + std::atomic done{false}; + code result = error::unknown; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await manager.add(peer); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(result == error::success); + REQUIRE(manager.count_snapshot() == 1); +} + +TEST_CASE("peer_manager add multiple peers", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::vector peers; + for (int i = 0; i < 5; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + peers.push_back(peer); + } + + std::atomic added{0}; + + for (auto const& peer : peers) { + ::asio::co_spawn(ctx, [&, peer]() -> ::asio::awaitable { + auto result = co_await manager.add(peer); + if (result == error::success) { + ++added; + } + }, ::asio::detached); + } + + run_until_pm(ctx, [&]{ return added.load() >= 5; }); + + REQUIRE(added == 5); + REQUIRE(manager.count_snapshot() == 5); +} + +TEST_CASE("peer_manager add duplicate nonce rejected", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + auto peer1 = make_test_peer(ctx); + peer1->set_nonce(12345); + + auto peer2 = make_test_peer(ctx); + peer2->set_nonce(12345); // Same nonce + + std::atomic done{false}; + code result1 = error::unknown; + code result2 = error::unknown; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result1 = co_await manager.add(peer1); + result2 = co_await manager.add(peer2); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(result1 == error::success); + REQUIRE(result2 == error::address_in_use); + REQUIRE(manager.count_snapshot() == 1); +} + +TEST_CASE("peer_manager add null peer rejected", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::atomic done{false}; + code result = error::unknown; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await manager.add(nullptr); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(result == error::operation_failed); + REQUIRE(manager.count_snapshot() == 0); +} + +TEST_CASE("peer_manager remove peer", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + + std::atomic done{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await manager.add(peer); + REQUIRE(manager.count_snapshot() == 1); + + co_await manager.remove(peer); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(manager.count_snapshot() == 0); +} + +TEST_CASE("peer_manager remove by nonce", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + + std::atomic done{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await manager.add(peer); + REQUIRE(manager.count_snapshot() == 1); + + co_await manager.remove_by_nonce(12345); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(manager.count_snapshot() == 0); +} + +TEST_CASE("peer_manager remove nonexistent is safe", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::atomic done{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await manager.remove_by_nonce(99999); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(manager.count_snapshot() == 0); +} + +// ============================================================================= +// Capacity Tests +// ============================================================================= + +TEST_CASE("peer_manager capacity limit", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 3); // Max 3 peers + + std::vector peers; + for (int i = 0; i < 5; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + peers.push_back(peer); + } + + std::atomic success_count{0}; + std::atomic rejected_count{0}; + std::atomic done_count{0}; + + for (auto const& peer : peers) { + ::asio::co_spawn(ctx, [&, peer]() -> ::asio::awaitable { + auto result = co_await manager.add(peer); + if (result == error::success) { + ++success_count; + } else if (result == error::channel_stopped) { + ++rejected_count; + } + ++done_count; + }, ::asio::detached); + } + + run_until_pm(ctx, [&]{ return done_count.load() >= 5; }); + + REQUIRE(success_count == 3); + REQUIRE(rejected_count == 2); + REQUIRE(manager.count_snapshot() == 3); +} + +// ============================================================================= +// Lookup Tests +// ============================================================================= + +TEST_CASE("peer_manager exists by nonce", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + + std::atomic done{false}; + bool exists_before = true; + bool exists_after = false; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + exists_before = co_await manager.exists_by_nonce(12345); + co_await manager.add(peer); + exists_after = co_await manager.exists_by_nonce(12345); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(!exists_before); + REQUIRE(exists_after); +} + +TEST_CASE("peer_manager find by nonce", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + + std::atomic done{false}; + peer_session::ptr found_before = nullptr; + peer_session::ptr found_after = nullptr; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + found_before = co_await manager.find_by_nonce(12345); + co_await manager.add(peer); + found_after = co_await manager.find_by_nonce(12345); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(found_before == nullptr); + REQUIRE(found_after != nullptr); + REQUIRE(found_after.get() == peer.get()); +} + +TEST_CASE("peer_manager count", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::atomic done{false}; + size_t count1 = 999; + size_t count2 = 999; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + count1 = co_await manager.count(); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + co_await manager.add(peer); + + count2 = co_await manager.count(); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(count1 == 0); + REQUIRE(count2 == 1); +} + +TEST_CASE("peer_manager all", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::vector added_peers; + for (int i = 0; i < 3; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + added_peers.push_back(peer); + } + + std::atomic done{false}; + std::vector retrieved_peers; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + for (auto const& peer : added_peers) { + co_await manager.add(peer); + } + retrieved_peers = co_await manager.all(); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(retrieved_peers.size() == 3); +} + +// ============================================================================= +// for_each Tests +// ============================================================================= + +TEST_CASE("peer_manager for_each", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::vector peers; + for (int i = 0; i < 3; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + peers.push_back(peer); + } + + std::atomic done{false}; + std::atomic visited_count{0}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + for (auto const& peer : peers) { + co_await manager.add(peer); + } + + co_await manager.for_each([&](peer_session::ptr) { + ++visited_count; + }); + + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(visited_count == 3); +} + +TEST_CASE("peer_manager for_each skips stopped peers", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::vector peers; + for (int i = 0; i < 3; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + peers.push_back(peer); + } + + // Stop one peer + peers[1]->stop(); + + std::atomic done{false}; + std::atomic visited_count{0}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + for (auto const& peer : peers) { + co_await manager.add(peer); + } + + co_await manager.for_each([&](peer_session::ptr) { + ++visited_count; + }); + + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(visited_count == 2); // Only 2 active peers visited +} + +// ============================================================================= +// Lifecycle Tests +// ============================================================================= + +TEST_CASE("peer_manager stop_all", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + std::vector peers; + for (int i = 0; i < 3; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + peers.push_back(peer); + } + + std::atomic done{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + for (auto const& peer : peers) { + co_await manager.add(peer); + } + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(!manager.stopped()); + REQUIRE(manager.count_snapshot() == 3); + + manager.stop_all(); + REQUIRE(manager.stopped()); + + // Run io_context to process the posted stop operation + // poll() processes all ready handlers without blocking + ctx.restart(); + ctx.poll(); + + REQUIRE(manager.count_snapshot() == 0); + + // All peers should be stopped + for (auto const& peer : peers) { + REQUIRE(peer->stopped()); + } +} + +TEST_CASE("peer_manager stop_all is idempotent", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + manager.stop_all(); + REQUIRE(manager.stopped()); + + manager.stop_all(); // Second call should be safe + REQUIRE(manager.stopped()); +} + +TEST_CASE("peer_manager add after stop rejected", "[peer_manager]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + manager.stop_all(); + + auto peer = make_test_peer(ctx); + peer->set_nonce(12345); + + std::atomic done{false}; + code result = error::unknown; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await manager.add(peer); + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + REQUIRE(result == error::service_stopped); +} + +// ============================================================================= +// Concurrent Access Tests +// ============================================================================= + +TEST_CASE("peer_manager concurrent add/remove", "[peer_manager][concurrent]") { + ::asio::io_context ctx; + peer_manager manager(ctx.get_executor(), 100); + + constexpr int num_operations = 50; + std::atomic completed{0}; + + // Spawn many concurrent add operations + for (int i = 0; i < num_operations; ++i) { + ::asio::co_spawn(ctx, [&, i]() -> ::asio::awaitable { + auto peer = make_test_peer(ctx); + peer->set_nonce(static_cast(i)); + co_await manager.add(peer); + + // Immediately remove half + if (i % 2 == 0) { + co_await manager.remove(peer); + } + + ++completed; + }, ::asio::detached); + } + + run_until_pm(ctx, [&]{ return completed.load() >= num_operations; }, 5000ms); + + REQUIRE(completed == num_operations); + // Half should remain (odd numbered) + REQUIRE(manager.count_snapshot() == num_operations / 2); +} + +// ============================================================================= +// Destructor Test +// ============================================================================= + +TEST_CASE("peer_manager destructor stops peers", "[peer_manager]") { + ::asio::io_context ctx; + std::vector peers; + + { + peer_manager manager(ctx.get_executor(), 100); + + for (int i = 0; i < 3; ++i) { + auto peer = make_test_peer(ctx); + peer->set_nonce(1000 + i); + peers.push_back(peer); + } + + std::atomic done{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + for (auto const& peer : peers) { + co_await manager.add(peer); + } + done = true; + }, ::asio::detached); + + run_until_pm(ctx, [&]{ return done.load(); }); + + // manager destructor called here + } + + // Wait for stop to propagate (async post to strand from destructor) + run_until_pm(ctx, [&]{ + for (auto const& peer : peers) { + if (!peer->stopped()) return false; + } + return true; + }); + + // All peers should be stopped + for (auto const& peer : peers) { + REQUIRE(peer->stopped()); + } +} From bae2e929d850fdadbf28f3aa191f4232684822e0 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 14:08:14 +0100 Subject: [PATCH 05/14] feat(network): add coroutine-based protocol functions (Phase 5) (#145) Implement protocol logic as free functions using C++20 coroutines: - wait_for_message() and wait_for_any_message() helpers - perform_handshake() for version/verack exchange - run_ping_pong() for keepalive loop - request_addresses() and send_addresses() for addr protocol These replace the complex protocol class hierarchy with simple, composable coroutine functions that operate on peer_session. --- src/network/CMakeLists.txt | 3 + src/network/include/kth/network.hpp | 1 + .../include/kth/network/protocols_coro.hpp | 163 +++++++ src/network/src/protocols_coro.cpp | 371 ++++++++++++++++ src/network/test/protocols_coro.cpp | 407 ++++++++++++++++++ 5 files changed, 945 insertions(+) create mode 100644 src/network/include/kth/network/protocols_coro.hpp create mode 100644 src/network/src/protocols_coro.cpp create mode 100644 src/network/test/protocols_coro.cpp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 2ff30359..02a5d798 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -117,6 +117,7 @@ set(kth_headers include/kth/network/protocols/protocol.hpp include/kth/network/protocols/protocol_ping_60001.hpp include/kth/network/protocols/protocol_reject_70002.hpp + include/kth/network/protocols_coro.hpp include/kth/network/settings.hpp include/kth/network.hpp ) @@ -146,6 +147,7 @@ set(kth_sources src/p2p.cpp src/peer_session.cpp src/peer_manager.cpp + src/protocols_coro.cpp src/proxy.cpp src/settings.cpp ) @@ -186,6 +188,7 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") test/p2p.cpp test/peer_manager.cpp test/peer_session.cpp + test/protocols_coro.cpp ) target_include_directories(kth_network_test PUBLIC $) diff --git a/src/network/include/kth/network.hpp b/src/network/include/kth/network.hpp index 3cc8f306..b90129dd 100644 --- a/src/network/include/kth/network.hpp +++ b/src/network/include/kth/network.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/src/network/include/kth/network/protocols_coro.hpp b/src/network/include/kth/network/protocols_coro.hpp new file mode 100644 index 00000000..d50bf503 --- /dev/null +++ b/src/network/include/kth/network/protocols_coro.hpp @@ -0,0 +1,163 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NETWORK_PROTOCOLS_CORO_HPP +#define KTH_NETWORK_PROTOCOLS_CORO_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace kth::network { + +// ============================================================================= +// Message Helpers +// ============================================================================= + +/// Wait for a specific message type from the peer +/// Returns the deserialized message or an error code +/// @param peer The peer session to receive from +/// @param timeout Maximum time to wait for the message +template +::asio::awaitable> wait_for_message( + peer_session& peer, + std::chrono::seconds timeout) +{ + using namespace ::asio::experimental::awaitable_operators; + + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor, timeout); + + // Race between message receive and timeout + auto result = co_await ( + peer.messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + // Check which completed first + if (result.index() == 1) { + // Timeout won + co_return std::unexpected(error::channel_timeout); + } + + // Message received + auto& [ec, raw] = std::get<0>(result); + if (ec) { + co_return std::unexpected(error::channel_stopped); + } + + // Check command matches expected type + if (raw.heading.command() != Message::command) { + // Wrong message type - could handle differently + co_return std::unexpected(error::bad_stream); + } + + // Deserialize the message + byte_reader reader(raw.payload); + auto msg = Message::from_data(reader, peer.negotiated_version()); + if (!msg) { + co_return std::unexpected(error::bad_stream); + } + + co_return std::move(*msg); +} + +/// Wait for any message from the peer (returns raw_message) +/// @param peer The peer session to receive from +/// @param timeout Maximum time to wait +::asio::awaitable> wait_for_any_message( + peer_session& peer, + std::chrono::seconds timeout); + +// ============================================================================= +// Version Handshake Protocol +// ============================================================================= + +/// Configuration for version handshake +struct handshake_config { + uint32_t protocol_version; // Our protocol version + uint64_t services; // Our services + uint64_t invalid_services; // Services we reject + uint32_t minimum_version; // Minimum peer version we accept + uint64_t minimum_services; // Minimum peer services we accept + std::string user_agent; // Our user agent string + uint32_t start_height; // Our current block height + uint64_t nonce; // Connection nonce + std::chrono::seconds timeout; // Handshake timeout + std::vector user_agent_blacklist; // Blacklisted user agents +}; + +/// Result of a successful handshake +struct handshake_result { + domain::message::version::const_ptr peer_version; + uint32_t negotiated_version; +}; + +/// Perform version handshake with a peer +/// Exchanges version messages and negotiates protocol version +/// @param peer The peer session +/// @param config Handshake configuration +/// @return handshake_result on success, error code on failure +[[nodiscard]] +KN_API ::asio::awaitable> perform_handshake( + peer_session& peer, + handshake_config const& config); + +/// Create handshake config from network settings +[[nodiscard]] +KN_API handshake_config make_handshake_config( + settings const& network_settings, + uint32_t current_height, + uint64_t nonce); + +// ============================================================================= +// Ping/Pong Protocol +// ============================================================================= + +/// Run ping/pong loop with a peer +/// Sends periodic pings and responds to incoming pings +/// Runs until the peer is stopped or an error occurs +/// @param peer The peer session +/// @param ping_interval Time between pings +/// @return Error code when loop terminates +[[nodiscard]] +KN_API ::asio::awaitable run_ping_pong( + peer_session& peer, + std::chrono::seconds ping_interval); + +// ============================================================================= +// Address Protocol +// ============================================================================= + +/// Request addresses from a peer +/// @param peer The peer session +/// @param timeout Maximum time to wait for response +/// @return Vector of addresses or error +[[nodiscard]] +KN_API ::asio::awaitable> request_addresses( + peer_session& peer, + std::chrono::seconds timeout); + +/// Send our addresses to a peer +/// @param peer The peer session +/// @param addresses Addresses to send +[[nodiscard]] +KN_API ::asio::awaitable send_addresses( + peer_session& peer, + domain::message::address const& addresses); + +} // namespace kth::network + +#endif // KTH_NETWORK_PROTOCOLS_CORO_HPP diff --git a/src/network/src/protocols_coro.cpp b/src/network/src/protocols_coro.cpp new file mode 100644 index 00000000..415ceb81 --- /dev/null +++ b/src/network/src/protocols_coro.cpp @@ -0,0 +1,371 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include + +namespace kth::network { + +using namespace ::asio::experimental::awaitable_operators; +using namespace std::chrono_literals; + +// ============================================================================= +// Message Helpers +// ============================================================================= + +::asio::awaitable> wait_for_any_message( + peer_session& peer, + std::chrono::seconds timeout) +{ + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor, timeout); + + auto result = co_await ( + peer.messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + co_return std::unexpected(error::channel_timeout); + } + + auto& [ec, raw] = std::get<0>(result); + if (ec) { + co_return std::unexpected(error::channel_stopped); + } + + co_return raw; +} + +// ============================================================================= +// Version Handshake Protocol +// ============================================================================= + +namespace { + +domain::message::version make_version_message( + handshake_config const& config, + infrastructure::config::authority const& peer_authority) +{ + domain::message::version version; + version.set_value(config.protocol_version); + version.set_services(config.services); + version.set_timestamp(static_cast(zulu_time())); + version.set_address_receiver(peer_authority.to_network_address()); + version.set_nonce(config.nonce); + version.set_user_agent(config.user_agent); + version.set_start_height(config.start_height); + + // The peer's services cannot be reflected, so zero it + version.address_receiver().set_services(domain::message::version::service::none); + + // We match our declared services + version.address_sender().set_services(config.services); + + return version; +} + +bool is_user_agent_blacklisted( + std::string const& user_agent, + std::vector const& blacklist) +{ + return std::any_of(blacklist.begin(), blacklist.end(), + [&user_agent](std::string const& blacklisted) { + if (blacklisted.size() <= user_agent.size()) { + return std::equal(blacklisted.begin(), blacklisted.end(), user_agent.begin()); + } + return std::equal(user_agent.begin(), user_agent.end(), blacklisted.begin()); + }); +} + +bool validate_peer_version( + domain::message::version const& peer_version, + handshake_config const& config, + infrastructure::config::authority const& authority) +{ + // Check blacklist + if (is_user_agent_blacklisted(peer_version.user_agent(), config.user_agent_blacklist)) { + spdlog::debug("[protocol] Invalid user agent (blacklisted) for peer [{}] user agent: {}", + authority, peer_version.user_agent()); + return false; + } + + // Check invalid services + if ((peer_version.services() & config.invalid_services) != 0) { + spdlog::debug("[protocol] Invalid peer services ({}) for [{}]", + peer_version.services(), authority); + return false; + } + + // Check minimum services + if ((peer_version.services() & config.minimum_services) != config.minimum_services) { + spdlog::debug("[protocol] Insufficient peer services ({}) for [{}]", + peer_version.services(), authority); + return false; + } + + // Check minimum version + if (peer_version.value() < config.minimum_version) { + spdlog::debug("[protocol] Insufficient peer protocol version ({}) for [{}]", + peer_version.value(), authority); + return false; + } + + return true; +} + +} // anonymous namespace + +::asio::awaitable> perform_handshake( + peer_session& peer, + handshake_config const& config) +{ + auto const& authority = peer.authority(); + + spdlog::debug("[protocol] Starting handshake with [{}]", authority); + + // Send our version message + auto version_msg = make_version_message(config, authority); + auto send_ec = co_await peer.send(version_msg); + if (send_ec != error::success) { + spdlog::debug("[protocol] Failed to send version to [{}]", authority); + co_return std::unexpected(send_ec); + } + + // We need to receive both version and verack from the peer + // The order may vary, so we track what we've received + bool got_version = false; + bool got_verack = false; + domain::message::version::const_ptr peer_version; + + auto deadline = std::chrono::steady_clock::now() + config.timeout; + + while (!got_version || !got_verack) { + auto remaining = std::chrono::duration_cast( + deadline - std::chrono::steady_clock::now()); + + if (remaining <= 0s) { + spdlog::debug("[protocol] Handshake timeout with [{}]", authority); + co_return std::unexpected(error::channel_timeout); + } + + // Wait for next message + auto msg_result = co_await wait_for_any_message(peer, remaining); + if (!msg_result) { + spdlog::debug("[protocol] Failed to receive message from [{}]: {}", + authority, msg_result.error().message()); + co_return std::unexpected(msg_result.error()); + } + + auto const& raw = *msg_result; + auto const& command = raw.heading.command(); + + if (command == domain::message::version::command && !got_version) { + // Parse version message + byte_reader reader(raw.payload); + auto version_result = domain::message::version::from_data(reader, peer.negotiated_version()); + if (!version_result) { + spdlog::debug("[protocol] Failed to parse version from [{}]", authority); + co_return std::unexpected(error::bad_stream); + } + auto version = std::make_shared(std::move(*version_result)); + + spdlog::debug("[protocol] Received version from [{}] protocol ({}) user agent: {}", + authority, version->value(), version->user_agent()); + + // Validate + if (!validate_peer_version(*version, config, authority)) { + co_return std::unexpected(error::channel_stopped); + } + + peer_version = version; + got_version = true; + + // Send verack in response + auto verack_ec = co_await peer.send(domain::message::verack{}); + if (verack_ec != error::success) { + spdlog::debug("[protocol] Failed to send verack to [{}]", authority); + co_return std::unexpected(verack_ec); + } + } + else if (command == domain::message::verack::command && !got_verack) { + spdlog::debug("[protocol] Received verack from [{}]", authority); + got_verack = true; + } + else { + // Unexpected message during handshake - log but continue + spdlog::debug("[protocol] Unexpected message '{}' during handshake with [{}]", + command, authority); + } + } + + // Calculate negotiated version + auto negotiated = std::min(peer_version->value(), config.protocol_version); + + // Update peer session + peer.set_peer_version(peer_version); + peer.set_negotiated_version(negotiated); + + spdlog::debug("[protocol] Handshake complete with [{}], negotiated version {}", + authority, negotiated); + + co_return handshake_result{peer_version, negotiated}; +} + +handshake_config make_handshake_config( + settings const& network_settings, + uint32_t current_height, + uint64_t nonce) +{ + return handshake_config{ + .protocol_version = network_settings.protocol_maximum, + .services = network_settings.services, + .invalid_services = network_settings.invalid_services, + .minimum_version = network_settings.protocol_minimum, + .minimum_services = domain::message::version::service::none, + .user_agent = network_settings.user_agent, + .start_height = current_height, + .nonce = nonce, + .timeout = std::chrono::seconds(network_settings.channel_handshake_seconds), + .user_agent_blacklist = network_settings.user_agent_blacklist + }; +} + +// ============================================================================= +// Ping/Pong Protocol +// ============================================================================= + +::asio::awaitable run_ping_pong( + peer_session& peer, + std::chrono::seconds ping_interval) +{ + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer ping_timer(executor); + + uint64_t last_ping_nonce = 0; + + while (!peer.stopped()) { + // Wait for either: + // 1. Ping interval expires -> send ping + // 2. Message received -> check if it's ping/pong + ping_timer.expires_after(ping_interval); + + auto result = co_await ( + peer.messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + ping_timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (peer.stopped()) { + break; + } + + if (result.index() == 1) { + // Timer expired - send ping + auto [timer_ec] = std::get<1>(result); + if (!timer_ec) { + pseudo_random::fill(reinterpret_cast(&last_ping_nonce), sizeof(last_ping_nonce)); + domain::message::ping ping_msg(last_ping_nonce); + + auto ec = co_await peer.send(ping_msg); + if (ec != error::success) { + spdlog::debug("[protocol] Failed to send ping to [{}]", peer.authority()); + co_return ec; + } + + spdlog::trace("[protocol] Sent ping to [{}] nonce={}", peer.authority(), last_ping_nonce); + } + } + else { + // Message received + auto& [ec, raw] = std::get<0>(result); + if (ec) { + co_return error::channel_stopped; + } + + auto const& command = raw.heading.command(); + + if (command == domain::message::ping::command) { + // Received ping - respond with pong + byte_reader reader(raw.payload); + auto ping_result = domain::message::ping::from_data(reader, peer.negotiated_version()); + if (ping_result) { + domain::message::pong pong_msg(ping_result->nonce()); + auto pong_ec = co_await peer.send(pong_msg); + if (pong_ec != error::success) { + spdlog::debug("[protocol] Failed to send pong to [{}]", peer.authority()); + } + spdlog::trace("[protocol] Responded pong to [{}]", peer.authority()); + } + } + else if (command == domain::message::pong::command) { + // Received pong - could verify nonce matches our last ping + byte_reader pong_reader(raw.payload); + auto pong_result = domain::message::pong::from_data(pong_reader, peer.negotiated_version()); + if (pong_result) { + spdlog::trace("[protocol] Received pong from [{}] nonce={}", + peer.authority(), pong_result->nonce()); + } + } + // Other messages are ignored by this protocol + } + } + + co_return error::channel_stopped; +} + +// ============================================================================= +// Address Protocol +// ============================================================================= + +::asio::awaitable> request_addresses( + peer_session& peer, + std::chrono::seconds timeout) +{ + // Send getaddr + auto ec = co_await peer.send(domain::message::get_address{}); + if (ec != error::success) { + co_return std::unexpected(ec); + } + + // Wait for addr response + auto deadline = std::chrono::steady_clock::now() + timeout; + + while (true) { + auto remaining = std::chrono::duration_cast( + deadline - std::chrono::steady_clock::now()); + + if (remaining <= 0s) { + co_return std::unexpected(error::channel_timeout); + } + + auto msg_result = co_await wait_for_any_message(peer, remaining); + if (!msg_result) { + co_return std::unexpected(msg_result.error()); + } + + auto const& raw = *msg_result; + if (raw.heading.command() == domain::message::address::command) { + byte_reader reader(raw.payload); + auto addr_result = domain::message::address::from_data(reader, peer.negotiated_version()); + if (!addr_result) { + co_return std::unexpected(error::bad_stream); + } + co_return std::move(*addr_result); + } + // Continue waiting for addr message + } +} + +::asio::awaitable send_addresses( + peer_session& peer, + domain::message::address const& addresses) +{ + co_return co_await peer.send(addresses); +} + +} // namespace kth::network diff --git a/src/network/test/protocols_coro.cpp b/src/network/test/protocols_coro.cpp new file mode 100644 index 00000000..e55ff384 --- /dev/null +++ b/src/network/test/protocols_coro.cpp @@ -0,0 +1,407 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace kth; +using namespace kth::network; +using namespace std::chrono_literals; + +// ============================================================================= +// Test helpers +// ============================================================================= + +std::pair<::asio::ip::tcp::socket, ::asio::ip::tcp::socket> +make_connected_sockets_proto(::asio::io_context& ctx) { + ::asio::ip::tcp::acceptor acceptor(ctx, {::asio::ip::tcp::v4(), 0}); + auto port = acceptor.local_endpoint().port(); + + ::asio::ip::tcp::socket client(ctx); + ::asio::ip::tcp::socket server(ctx); + + std::thread accept_thread([&]() { + server = acceptor.accept(); + }); + + client.connect({::asio::ip::address_v4::loopback(), port}); + + accept_thread.join(); + + return {std::move(client), std::move(server)}; +} + +template +void run_until_proto(::asio::io_context& ctx, Predicate pred, std::chrono::milliseconds timeout = 1000ms) { + auto deadline = std::chrono::steady_clock::now() + timeout; + while (!pred() && std::chrono::steady_clock::now() < deadline) { + ctx.run_for(10ms); + } +} + +network::settings make_test_settings_proto() { + network::settings settings; + settings.identifier = 0xe8f3e1e3; // BCH testnet magic + settings.protocol_maximum = 70015; + settings.protocol_minimum = 31402; + settings.services = 0; + settings.invalid_services = 0; + settings.validate_checksum = true; + settings.channel_inactivity_minutes = 1; + settings.channel_expiration_minutes = 5; + settings.channel_handshake_seconds = 30; + settings.inbound_port = 18333; + settings.user_agent = "/KnuthTest:0.1.0/"; + return settings; +} + +// Build a valid Bitcoin protocol message +data_chunk build_message_proto(std::string const& command, data_chunk const& payload, uint32_t magic) { + data_chunk message; + message.reserve(24 + payload.size()); + + auto const magic_le = to_little_endian(magic); + message.insert(message.end(), magic_le.begin(), magic_le.end()); + + std::array cmd{}; + std::copy_n(command.begin(), std::min(command.size(), size_t{12}), cmd.begin()); + message.insert(message.end(), cmd.begin(), cmd.end()); + + auto const size_le = to_little_endian(static_cast(payload.size())); + message.insert(message.end(), size_le.begin(), size_le.end()); + + auto const hash = bitcoin_hash(payload); + message.insert(message.end(), hash.begin(), hash.begin() + 4); + + message.insert(message.end(), payload.begin(), payload.end()); + + return message; +} + +// ============================================================================= +// handshake_config Tests +// ============================================================================= + +TEST_CASE("make_handshake_config from settings", "[protocols_coro]") { + auto settings = make_test_settings_proto(); + + auto config = make_handshake_config(settings, 100000, 12345); + + REQUIRE(config.protocol_version == 70015); + REQUIRE(config.minimum_version == 31402); + REQUIRE(config.user_agent == "/KnuthTest:0.1.0/"); + REQUIRE(config.start_height == 100000); + REQUIRE(config.nonce == 12345); + REQUIRE(config.timeout == 30s); +} + +// ============================================================================= +// wait_for_any_message Tests +// ============================================================================= + +TEST_CASE("wait_for_any_message receives message", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + // Start session + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + + // Wait for message + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await wait_for_any_message(*peer, 5s); + done = true; + }, ::asio::detached); + + ctx.run_for(50ms); + + // Send a ping message from client + auto ping_msg = build_message_proto("ping", {}, settings.identifier); + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(ping_msg), write_ec); + REQUIRE(!write_ec); + + run_until_proto(ctx, [&]{ return done.load(); }); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(result.has_value()); + REQUIRE(result->heading.command() == "ping"); +} + +TEST_CASE("wait_for_any_message timeout", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await wait_for_any_message(*peer, 1s); // Short timeout + done = true; + }, ::asio::detached); + + // Don't send anything - should timeout + run_until_proto(ctx, [&]{ return done.load(); }, 2000ms); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(!result.has_value()); + REQUIRE(result.error() == error::channel_timeout); +} + +// ============================================================================= +// Handshake Tests (simulated peer) +// ============================================================================= + +TEST_CASE("perform_handshake success", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + auto config = make_handshake_config(settings, 100000, 12345); + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + // Start peer session + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + + // Run handshake + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await perform_handshake(*peer, config); + done = true; + }, ::asio::detached); + + ctx.run_for(50ms); + + // Simulate remote peer: receive version, send version + verack + + // Read the version message our peer sent + std::array recv_buf; + std::error_code read_ec; + auto n = client.read_some(::asio::buffer(recv_buf), read_ec); + REQUIRE(!read_ec); + REQUIRE(n > 24); // At least header size + + // Create and send remote version + domain::message::version remote_version; + remote_version.set_value(70015); + remote_version.set_services(0); + remote_version.set_timestamp(static_cast(zulu_time())); + remote_version.set_nonce(99999); + remote_version.set_user_agent("/RemotePeer:1.0/"); + remote_version.set_start_height(50000); + + auto version_payload = remote_version.to_data(70015); + auto version_msg = build_message_proto("version", version_payload, settings.identifier); + ::asio::write(client, ::asio::buffer(version_msg), read_ec); + REQUIRE(!read_ec); + + ctx.run_for(50ms); + + // Send verack + auto verack_msg = build_message_proto("verack", {}, settings.identifier); + ::asio::write(client, ::asio::buffer(verack_msg), read_ec); + REQUIRE(!read_ec); + + run_until_proto(ctx, [&]{ return done.load(); }, 2000ms); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(result.has_value()); + REQUIRE(result->peer_version != nullptr); + REQUIRE(result->peer_version->user_agent() == "/RemotePeer:1.0/"); + REQUIRE(result->negotiated_version == 70015); +} + +TEST_CASE("perform_handshake timeout", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + auto config = make_handshake_config(settings, 100000, 12345); + config.timeout = 1s; // Short timeout for test + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await perform_handshake(*peer, config); + done = true; + }, ::asio::detached); + + // Don't respond - should timeout + run_until_proto(ctx, [&]{ return done.load(); }, 3000ms); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(!result.has_value()); + REQUIRE(result.error() == error::channel_timeout); +} + +TEST_CASE("perform_handshake rejects low version peer", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + auto config = make_handshake_config(settings, 100000, 12345); + config.minimum_version = 70000; // Require higher version + + std::atomic done{false}; + std::expected result = std::unexpected(error::unknown); + + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result = co_await perform_handshake(*peer, config); + done = true; + }, ::asio::detached); + + ctx.run_for(50ms); + + // Read version from our peer + std::array recv_buf; + std::error_code read_ec; + client.read_some(::asio::buffer(recv_buf), read_ec); + + // Send version with low protocol version + domain::message::version remote_version; + remote_version.set_value(31402); // Too low + remote_version.set_services(0); + remote_version.set_timestamp(static_cast(zulu_time())); + remote_version.set_nonce(99999); + remote_version.set_user_agent("/OldPeer:0.1/"); + remote_version.set_start_height(50000); + + auto version_payload = remote_version.to_data(31402); + auto version_msg = build_message_proto("version", version_payload, settings.identifier); + ::asio::write(client, ::asio::buffer(version_msg), read_ec); + + run_until_proto(ctx, [&]{ return done.load(); }, 2000ms); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(!result.has_value()); + REQUIRE(result.error() == error::channel_stopped); +} + +// ============================================================================= +// Ping/Pong Tests +// ============================================================================= + +TEST_CASE("run_ping_pong responds to ping", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + + // Start peer session and ping/pong loop + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + ::asio::co_spawn(ctx, run_ping_pong(*peer, 60s), ::asio::detached); // Long interval so we don't auto-ping + + ctx.run_for(50ms); + + // Send a ping from client + domain::message::ping ping{123456789}; + auto ping_payload = ping.to_data(70015); + auto ping_msg = build_message_proto("ping", ping_payload, settings.identifier); + + std::error_code write_ec; + ::asio::write(client, ::asio::buffer(ping_msg), write_ec); + REQUIRE(!write_ec); + + // Should receive pong in response + std::array recv_buf; + std::atomic bytes_received{0}; + std::string received_command; + + client.async_read_some(::asio::buffer(recv_buf), [&](auto ec, size_t n) { + if (!ec && n >= 24) { + bytes_received = n; + // Extract command from header (bytes 4-16) + std::string cmd(reinterpret_cast(recv_buf.data() + 4), 12); + cmd = cmd.c_str(); // Trim nulls + received_command = cmd; + } + }); + + run_until_proto(ctx, [&]{ return bytes_received.load() > 0; }); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(bytes_received > 0); + REQUIRE(received_command == "pong"); +} + +TEST_CASE("run_ping_pong sends periodic pings", "[protocols_coro]") { + ::asio::io_context ctx; + auto settings = make_test_settings_proto(); + auto [client, server] = make_connected_sockets_proto(ctx); + + auto peer = std::make_shared(std::move(server), settings); + + // Short ping interval for testing + ::asio::co_spawn(ctx, peer->run(), ::asio::detached); + ::asio::co_spawn(ctx, run_ping_pong(*peer, 1s), ::asio::detached); + + // Wait for a ping to be sent + std::array recv_buf; + std::atomic received_ping{false}; + + std::function read_handler; + read_handler = [&](std::error_code ec, size_t n) { + if (!ec && n >= 24) { + std::string cmd(reinterpret_cast(recv_buf.data() + 4), 12); + cmd = cmd.c_str(); + if (cmd == "ping") { + received_ping = true; + return; + } + } + if (!peer->stopped()) { + client.async_read_some(::asio::buffer(recv_buf), read_handler); + } + }; + client.async_read_some(::asio::buffer(recv_buf), read_handler); + + run_until_proto(ctx, [&]{ return received_ping.load(); }, 3000ms); + + peer->stop(); + ctx.run_for(10ms); + + REQUIRE(received_ping); +} From a7b768c01076e2912d9c30cac5f4d384a99aaad9 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 14:10:03 +0100 Subject: [PATCH 06/14] feat(network): add p2p_node unified networking class (Phase 6) (#146) Add p2p_node class that integrates all coroutine-based networking components into a unified P2P networking interface. Components: - p2p_node: Main networking class with lifecycle management - Uses async_connect/async_accept/async_listen from peer_session.hpp - Uses peer_manager for connection tracking - Uses protocols_coro for handshake, ping/pong, address requests - Supports seeding, inbound/outbound connections, broadcasting Features: - Coroutine-based API (asio::awaitable) - Automatic seeding when host pool is low - Configurable inbound/outbound connections - Top block tracking for version negotiation - Thread pool based execution Note: p2p_node will be renamed to p2p after legacy code removal in Phase 7 cleanup. --- src/network/CMakeLists.txt | 3 + src/network/include/kth/network.hpp | 1 + src/network/include/kth/network/p2p_node.hpp | 151 +++++++ src/network/src/p2p_node.cpp | 416 +++++++++++++++++++ src/network/test/p2p_node.cpp | 302 ++++++++++++++ 5 files changed, 873 insertions(+) create mode 100644 src/network/include/kth/network/p2p_node.hpp create mode 100644 src/network/src/p2p_node.cpp create mode 100644 src/network/test/p2p_node.cpp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 02a5d798..14bb4b37 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -99,6 +99,7 @@ set(kth_headers include/kth/network/channel.hpp include/kth/network/hosts.hpp include/kth/network/p2p.hpp + include/kth/network/p2p_node.hpp include/kth/network/sessions/session_outbound.hpp include/kth/network/sessions/session_seed.hpp include/kth/network/sessions/session_inbound.hpp @@ -145,6 +146,7 @@ set(kth_sources src/hosts.cpp src/message_subscriber.cpp src/p2p.cpp + src/p2p_node.cpp src/peer_session.cpp src/peer_manager.cpp src/protocols_coro.cpp @@ -186,6 +188,7 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") add_executable(kth_network_test test/p2p.cpp + test/p2p_node.cpp test/peer_manager.cpp test/peer_session.cpp test/protocols_coro.cpp diff --git a/src/network/include/kth/network.hpp b/src/network/include/kth/network.hpp index b90129dd..aa80b8ea 100644 --- a/src/network/include/kth/network.hpp +++ b/src/network/include/kth/network.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/src/network/include/kth/network/p2p_node.hpp b/src/network/include/kth/network/p2p_node.hpp new file mode 100644 index 00000000..db17ed20 --- /dev/null +++ b/src/network/include/kth/network/p2p_node.hpp @@ -0,0 +1,151 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NETWORK_P2P_NODE_HPP +#define KTH_NETWORK_P2P_NODE_HPP + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace kth::network { + +// ============================================================================= +// Connection result (combines peer_session with handshake info) +// ============================================================================= + +struct connection_result { + peer_session::ptr session; + handshake_result handshake; +}; + +// ============================================================================= +// P2P Node (main networking class) +// ============================================================================= + +class KN_API p2p_node { +public: + using ptr = std::shared_ptr; + using address = domain::message::network_address; + + explicit p2p_node(settings const& settings); + ~p2p_node(); + + // Lifecycle + // ------------------------------------------------------------------------- + + /// Start the node (load hosts, seed if needed) + ::asio::awaitable start(); + + /// Run the node (start accepting connections and connecting to peers) + ::asio::awaitable run(); + + /// Stop the node + void stop(); + + /// Block until all work is complete + void join(); + + // Properties + // ------------------------------------------------------------------------- + + [[nodiscard]] + settings const& network_settings() const; + + [[nodiscard]] + bool stopped() const; + + [[nodiscard]] + size_t connection_count() const; + + [[nodiscard]] + infrastructure::config::checkpoint top_block() const; + + void set_top_block(infrastructure::config::checkpoint const& top); + void set_top_block(infrastructure::config::checkpoint&& top); + + // Manual connections + // ------------------------------------------------------------------------- + + /// Connect to a specific peer and perform handshake + ::asio::awaitable> connect( + std::string const& host, + uint16_t port); + + // Host management + // ------------------------------------------------------------------------- + + [[nodiscard]] + size_t address_count() const; + + code store(address const& addr); + code fetch_address(address& out) const; + code remove(address const& addr); + + // Broadcasting + // ------------------------------------------------------------------------- + + /// Broadcast a message to all connected peers + template + ::asio::awaitable broadcast(Message const& message) { + co_return co_await manager_.broadcast(message); + } + + // Peer access + // ------------------------------------------------------------------------- + + /// Get the peer manager (for advanced use) + [[nodiscard]] + peer_manager& peers(); + + /// Get a copy of all connected peer sessions + [[nodiscard]] + std::vector get_peers() const; + +private: + // Internal coroutines + ::asio::awaitable run_seeding(); + ::asio::awaitable run_outbound(); + ::asio::awaitable run_inbound(); + ::asio::awaitable run_peer_protocols(peer_session::ptr peer); + ::asio::awaitable maintain_outbound_connections(); + + uint64_t generate_nonce(); + + settings const& settings_; + ::asio::thread_pool pool_; + peer_manager manager_; + hosts hosts_; + + // Acceptor for inbound connections + std::unique_ptr<::asio::ip::tcp::acceptor> acceptor_; + + std::atomic stopped_{true}; + std::atomic seeded_{false}; + kth::atomic top_block_; +}; + +} // namespace kth::network + +#endif // KTH_NETWORK_P2P_NODE_HPP diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp new file mode 100644 index 00000000..c126a352 --- /dev/null +++ b/src/network/src/p2p_node.cpp @@ -0,0 +1,416 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +namespace kth::network { + +using namespace ::asio::experimental::awaitable_operators; +using namespace std::chrono_literals; + +// ============================================================================= +// P2P Node implementation +// ============================================================================= + +p2p_node::p2p_node(settings const& settings) + : settings_(settings) + , pool_(settings.threads > 0 ? settings.threads : 1) + , manager_(pool_.get_executor()) + , hosts_(settings) + , top_block_({null_hash, 0}) +{} + +p2p_node::~p2p_node() { + stop(); + join(); +} + +::asio::awaitable p2p_node::start() { + if (!stopped_) { + co_return error::operation_failed; + } + + stopped_ = false; + + // Load hosts from file + auto ec = hosts_.start(); + if (ec) { + spdlog::error("[p2p_node] Failed to load hosts: {}", ec.message()); + co_return ec; + } + + spdlog::info("[p2p_node] Loaded {} host addresses", hosts_.count()); + + // Seed if needed + if (hosts_.count() < settings_.host_pool_capacity / 2) { + co_await run_seeding(); + } + + seeded_ = true; + co_return error::success; +} + +::asio::awaitable p2p_node::run() { + if (stopped_) { + co_return error::service_stopped; + } + + // Start inbound acceptor + ::asio::co_spawn(pool_.get_executor(), run_inbound(), ::asio::detached); + + // Start outbound connection manager + ::asio::co_spawn(pool_.get_executor(), run_outbound(), ::asio::detached); + + // Connect to configured manual peers + for (auto const& peer : settings_.peers) { + auto result = co_await connect(peer.host(), peer.port()); + if (!result) { + spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", + peer.host(), peer.port(), result.error().message()); + } + } + + co_return error::success; +} + +void p2p_node::stop() { + if (stopped_) { + return; + } + + stopped_ = true; + + // Stop acceptor + if (acceptor_) { + std::error_code ec; + acceptor_->close(ec); + } + + // Stop all peers + manager_.stop_all(); + + // Save hosts + hosts_.stop(); + + // Stop thread pool + pool_.stop(); +} + +void p2p_node::join() { + pool_.join(); +} + +// Properties +// ----------------------------------------------------------------------------- + +settings const& p2p_node::network_settings() const { + return settings_; +} + +bool p2p_node::stopped() const { + return stopped_; +} + +size_t p2p_node::connection_count() const { + return manager_.count_snapshot(); +} + +infrastructure::config::checkpoint p2p_node::top_block() const { + return top_block_.load(); +} + +void p2p_node::set_top_block(infrastructure::config::checkpoint const& top) { + top_block_.store(top); +} + +void p2p_node::set_top_block(infrastructure::config::checkpoint&& top) { + top_block_.store(std::move(top)); +} + +// Manual connections +// ----------------------------------------------------------------------------- + +::asio::awaitable> p2p_node::connect( + std::string const& host, + uint16_t port) +{ + if (stopped_) { + co_return std::unexpected(error::service_stopped); + } + + auto executor = co_await ::asio::this_coro::executor; + + // Use async_connect from peer_session.hpp + auto result = co_await async_connect( + executor, + host, + port, + settings_, + std::chrono::seconds(settings_.connect_timeout_seconds)); + + if (!result) { + co_return std::unexpected(result.error()); + } + + auto peer = *result; + + // Start the session's message pump + ::asio::co_spawn(executor, peer->run(), ::asio::detached); + + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + peer->stop(); + spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", + host, port, handshake_result.error().message()); + co_return std::unexpected(handshake_result.error()); + } + + spdlog::info("[p2p_node] Handshake complete with {}:{}, version {}", + host, port, handshake_result->negotiated_version); + + // Add to peer manager + auto ec = co_await manager_.add(peer); + if (ec != error::success) { + peer->stop(); + co_return std::unexpected(ec); + } + + // Start protocol handlers + ::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); + + co_return peer; +} + +// Host management +// ----------------------------------------------------------------------------- + +size_t p2p_node::address_count() const { + return hosts_.count(); +} + +code p2p_node::store(address const& addr) { + return hosts_.store(addr); +} + +code p2p_node::fetch_address(address& out) const { + return hosts_.fetch(out); +} + +code p2p_node::remove(address const& addr) { + return hosts_.remove(addr); +} + +// Peer access +// ----------------------------------------------------------------------------- + +peer_manager& p2p_node::peers() { + return manager_; +} + +std::vector p2p_node::get_peers() const { + // Note: This is a blocking call that runs the coroutine synchronously. + // For async access, use peers().all() directly. + std::vector result; + // For now, return empty - callers should use the async version + // TODO: Consider removing this sync method or implementing properly + return result; +} + +// Internal coroutines +// ----------------------------------------------------------------------------- + +::asio::awaitable p2p_node::run_seeding() { + spdlog::info("[p2p_node] Starting seeding from {} seeds", settings_.seeds.size()); + + auto executor = co_await ::asio::this_coro::executor; + + for (auto const& seed : settings_.seeds) { + if (stopped_) break; + + spdlog::debug("[p2p_node] Connecting to seed {}:{}", seed.host(), seed.port()); + + // Use async_connect from peer_session.hpp + auto result = co_await async_connect( + executor, + seed.host(), + seed.port(), + settings_, + std::chrono::seconds(settings_.connect_timeout_seconds)); + + if (!result) { + spdlog::debug("[p2p_node] Failed to connect to seed {}:{} - {}", + seed.host(), seed.port(), result.error().message()); + continue; + } + + auto peer = *result; + + // Start the session's message pump + ::asio::co_spawn(executor, peer->run(), ::asio::detached); + + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + peer->stop(); + spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", + seed.host(), seed.port(), handshake_result.error().message()); + continue; + } + + // Request addresses + auto addr_result = co_await request_addresses(*peer, 30s); + + if (addr_result) { + spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", + addr_result->addresses().size(), seed.host(), seed.port()); + + for (auto const& addr : addr_result->addresses()) { + hosts_.store(addr); + } + } + + // Disconnect from seed + peer->stop(); + } + + spdlog::info("[p2p_node] Seeding complete, {} addresses available", hosts_.count()); +} + +::asio::awaitable p2p_node::run_outbound() { + co_await maintain_outbound_connections(); +} + +::asio::awaitable p2p_node::run_inbound() { + if (settings_.inbound_port == 0) { + spdlog::info("[p2p_node] Inbound connections disabled (port 0)"); + co_return; + } + + auto executor = co_await ::asio::this_coro::executor; + + // Use async_listen from peer_session.hpp + auto listen_result = co_await async_listen(executor, settings_.inbound_port); + if (!listen_result) { + spdlog::error("[p2p_node] Failed to start listening: {}", listen_result.error().message()); + co_return; + } + + acceptor_ = std::make_unique<::asio::ip::tcp::acceptor>(std::move(*listen_result)); + + spdlog::info("[p2p_node] Listening on port {}", settings_.inbound_port); + + // Accept loop + while (!stopped_) { + // Use async_accept from peer_session.hpp + auto result = co_await async_accept(*acceptor_, settings_); + + if (!result) { + if (result.error() == error::service_stopped) { + break; + } + spdlog::debug("[p2p_node] Accept error: {}", result.error().message()); + continue; + } + + auto peer = *result; + + // Handle the new connection in a separate coroutine + ::asio::co_spawn(executor, [this, peer, executor]() -> ::asio::awaitable { + // Start the session's message pump + ::asio::co_spawn(executor, peer->run(), ::asio::detached); + + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + peer->stop(); + spdlog::debug("[p2p_node] Inbound handshake failed: {}", + handshake_result.error().message()); + co_return; + } + + spdlog::info("[p2p_node] Inbound handshake complete from {}, version {}", + peer->authority(), handshake_result->negotiated_version); + + // Add to peer manager + auto ec = co_await manager_.add(peer); + if (ec != error::success) { + peer->stop(); + co_return; + } + + // Start protocol handlers + co_await run_peer_protocols(peer); + }, ::asio::detached); + } +} + +::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { + // Run ping/pong to keep connection alive + co_await run_ping_pong(*peer, std::chrono::seconds(settings_.channel_heartbeat_minutes * 60)); +} + +::asio::awaitable p2p_node::maintain_outbound_connections() { + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + while (!stopped_) { + auto const current_count = manager_.count_snapshot(); + auto const target = settings_.outbound_connections; + + if (current_count < target) { + // Need more connections + auto const needed = target - current_count; + + for (size_t i = 0; i < needed && !stopped_; ++i) { + domain::message::network_address addr; + auto ec = hosts_.fetch(addr); + + if (ec) { + spdlog::debug("[p2p_node] No addresses available for outbound"); + break; + } + + auto const authority = infrastructure::config::authority(addr); + auto result = co_await connect(authority.to_hostname(), authority.port()); + + if (!result) { + spdlog::debug("[p2p_node] Failed to connect to {}: {}", + authority, result.error().message()); + hosts_.remove(addr); + } + } + } + + // Wait before next check + timer.expires_after(std::chrono::seconds(settings_.connect_batch_size > 0 ? 5 : 30)); + co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + } +} + +uint64_t p2p_node::generate_nonce() { + uint64_t nonce = 0; + pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); + return nonce; +} + +} // namespace kth::network diff --git a/src/network/test/p2p_node.cpp b/src/network/test/p2p_node.cpp new file mode 100644 index 00000000..584158fe --- /dev/null +++ b/src/network/test/p2p_node.cpp @@ -0,0 +1,302 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace kth; +using namespace kth::network; +using namespace std::chrono_literals; + +// ============================================================================= +// Test helpers +// ============================================================================= + +// Helper to run context with timeout and stop condition +template +void run_until_p2p(::asio::io_context& ctx, Predicate pred, std::chrono::milliseconds timeout = 1000ms) { + auto deadline = std::chrono::steady_clock::now() + timeout; + while (!pred() && std::chrono::steady_clock::now() < deadline) { + ctx.run_for(10ms); + } +} + +// Create default settings for testing +network::settings make_test_settings_p2p() { + network::settings settings; + settings.identifier = 0xe8f3e1e3; // BCH testnet magic + settings.protocol_maximum = 70015; + settings.validate_checksum = true; + settings.channel_inactivity_minutes = 1; + settings.channel_expiration_minutes = 5; + settings.inbound_port = 0; // Disable inbound for unit tests + settings.outbound_connections = 0; // Disable outbound for unit tests + settings.threads = 1; + settings.connect_timeout_seconds = 5; + settings.channel_handshake_seconds = 5; + return settings; +} + +// ============================================================================= +// Construction Tests +// ============================================================================= + +TEST_CASE("p2p_node construction", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + REQUIRE(node.stopped()); + REQUIRE(node.connection_count() == 0); +} + +TEST_CASE("p2p_node settings preserved", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + settings.identifier = 0x12345678; + settings.threads = 4; + + p2p_node node(settings); + + REQUIRE(node.network_settings().identifier == 0x12345678); + REQUIRE(node.network_settings().threads == 4); +} + +// ============================================================================= +// Top Block Tests +// ============================================================================= + +TEST_CASE("p2p_node top block default zero null hash", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + REQUIRE(node.top_block().height() == 0); + REQUIRE(node.top_block().hash() == null_hash); +} + +TEST_CASE("p2p_node set top block by const ref", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + size_t const expected_height = 42; + auto const expected_hash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"_hash; + + infrastructure::config::checkpoint const checkpoint{expected_hash, expected_height}; + node.set_top_block(checkpoint); + + REQUIRE(node.top_block().hash() == expected_hash); + REQUIRE(node.top_block().height() == expected_height); +} + +TEST_CASE("p2p_node set top block by rvalue", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + size_t const expected_height = 100; + auto const expected_hash = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hash; + + node.set_top_block({expected_hash, expected_height}); + + REQUIRE(node.top_block().hash() == expected_hash); + REQUIRE(node.top_block().height() == expected_height); +} + +// ============================================================================= +// Lifecycle Tests +// ============================================================================= + +TEST_CASE("p2p_node start stop", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + REQUIRE(node.stopped()); + + // Start requires running in a coroutine context + ::asio::io_context ctx; + std::atomic started{false}; + code start_result = error::unknown; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + start_result = co_await node.start(); + started = true; + }, ::asio::detached); + + run_until_p2p(ctx, [&]{ return started.load(); }, 2000ms); + + REQUIRE(started); + REQUIRE(start_result == error::success); + REQUIRE(!node.stopped()); + + node.stop(); + REQUIRE(node.stopped()); +} + +TEST_CASE("p2p_node double start fails", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + ::asio::io_context ctx; + std::atomic done_count{0}; + code result1 = error::unknown; + code result2 = error::unknown; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + result1 = co_await node.start(); + ++done_count; + result2 = co_await node.start(); // Second start should fail + ++done_count; + }, ::asio::detached); + + run_until_p2p(ctx, [&]{ return done_count.load() >= 2; }, 2000ms); + + REQUIRE(result1 == error::success); + REQUIRE(result2 == error::operation_failed); + + node.stop(); +} + +TEST_CASE("p2p_node stop is idempotent", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + ::asio::io_context ctx; + std::atomic started{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await node.start(); + started = true; + }, ::asio::detached); + + run_until_p2p(ctx, [&]{ return started.load(); }, 2000ms); + + node.stop(); + REQUIRE(node.stopped()); + + node.stop(); // Second stop should be safe + REQUIRE(node.stopped()); +} + +// ============================================================================= +// Connection Count Tests +// ============================================================================= + +TEST_CASE("p2p_node connection count starts at zero", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + REQUIRE(node.connection_count() == 0); +} + +// ============================================================================= +// Address Management Tests +// ============================================================================= + +TEST_CASE("p2p_node address count starts at zero", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + REQUIRE(node.address_count() == 0); +} + +// ============================================================================= +// Peer Manager Access Tests +// ============================================================================= + +TEST_CASE("p2p_node peers access", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + // Should be able to access peer manager + auto& manager = node.peers(); + REQUIRE(manager.count_snapshot() == 0); +} + +// ============================================================================= +// Connect Tests (requires network, marked as integration) +// ============================================================================= + +TEST_CASE("p2p_node connect to invalid host fails", "[p2p_node][integration]") { + auto settings = make_test_settings_p2p(); + settings.connect_timeout_seconds = 1; // Short timeout + p2p_node node(settings); + + ::asio::io_context ctx; + std::atomic done{false}; + code start_result = error::unknown; + std::expected connect_result; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + start_result = co_await node.start(); + if (start_result == error::success) { + connect_result = co_await node.connect("invalid.host.that.does.not.exist.local", 18333); + } + done = true; + }, ::asio::detached); + + run_until_p2p(ctx, [&]{ return done.load(); }, 5000ms); + + REQUIRE(done); + REQUIRE(start_result == error::success); + REQUIRE(!connect_result.has_value()); + + node.stop(); +} + +TEST_CASE("p2p_node connect when stopped fails", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + p2p_node node(settings); + + ::asio::io_context ctx; + std::atomic done{false}; + std::expected connect_result; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + // Don't start the node, try to connect + connect_result = co_await node.connect("localhost", 18333); + done = true; + }, ::asio::detached); + + run_until_p2p(ctx, [&]{ return done.load(); }, 1000ms); + + REQUIRE(done); + REQUIRE(!connect_result.has_value()); + REQUIRE(connect_result.error() == error::service_stopped); +} + +// ============================================================================= +// Destructor Tests +// ============================================================================= + +TEST_CASE("p2p_node destructor stops node", "[p2p_node]") { + auto settings = make_test_settings_p2p(); + + { + p2p_node node(settings); + + ::asio::io_context ctx; + std::atomic started{false}; + + ::asio::co_spawn(ctx, [&]() -> ::asio::awaitable { + co_await node.start(); + started = true; + }, ::asio::detached); + + run_until_p2p(ctx, [&]{ return started.load(); }, 2000ms); + + REQUIRE(!node.stopped()); + // destructor called here + } + + // Node should have been stopped by destructor + // (no crash = success) + REQUIRE(true); +} From 71dba293bb9cb63d255451996bf54c7f8f3aecda Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 18 Dec 2025 14:12:20 +0100 Subject: [PATCH 07/14] feature: Complete coroutine migration cleanup (Phase 7) (#147) - Complete Phase 7 of the coroutine migration with a fully functional P2P network layer - Delete legacy node sessions and protocols - Comment out legacy network code (to be deleted after full validation) - Add blockchain protocol declarations and implementations in protocols_coro - Add headers-first sync infrastructure (sync_session, header_organizer, validate_header) - Add TUI mining dashboard and display modes - All legacy session classes (session_inbound, session_outbound, session_manual, session_block_sync, session_header_sync) - All legacy protocol classes (protocol_block_in/out, protocol_header_sync, protocol_transaction_in/out, protocol_double_spend_proof_in/out) - Legacy sessions (session.cpp, session_*.cpp) - Legacy protocols (protocol_*.cpp) - Legacy core (p2p.cpp, proxy.cpp, channel.cpp, acceptor.cpp, connector.cpp, message_subscriber.cpp) - Legacy test (test/p2p.cpp) - Blockchain protocol declarations in protocols_coro.hpp (request_headers, request_block, send_inventory, etc.) - Full implementations in protocols_coro.cpp - sync_session: coordinates headers-first sync with peers - header_organizer: caches and validates headers during IBD with memory-aware batching - validate_header: header validation (PoW, checkpoints, chain continuity) - broadcaster template for async channel subscriptions - system_memory utilities for cross-platform memory estimation - block_chain::organize_headers_batch() for batch header storage - TUI mining dashboard with sync statistics - Display mode support (headless, tui, etc.) - coroutine-migration-status.md documenting current state and TODOs - [x] Compilation passes - [x] Unit tests pass - [x] Verified on real BCH mainnet: - Seeding works (obtains 1000+ addresses) - Outbound connections work - Version/verack handshake completes - Ping/pong keepalive works - Message reception works (inv, addr, getheaders, etc.) - Headers sync starts (receives 2000 headers per batch) --- .gitignore | 2 + CMakeLists.txt | 8 + conan.lock | 1 + conanfile.py | 25 +- doc/asio.md | 2936 +++++++++++++++++ doc/coroutine-migration-status.md | 151 + src/CMakeLists.txt | 7 +- src/blockchain/CMakeLists.txt | 8 +- src/blockchain/conanfile.py | 128 - src/blockchain/include/kth/blockchain.hpp | 4 +- .../kth/blockchain/interface/block_chain.hpp | 473 ++- .../kth/blockchain/interface/fast_chain.hpp | 115 - .../kth/blockchain/interface/safe_chain.hpp | 185 -- .../kth/blockchain/pools/block_organizer.hpp | 52 +- .../kth/blockchain/pools/header_organizer.hpp | 193 ++ .../pools/transaction_organizer.hpp | 93 +- .../kth/blockchain/pools/transaction_pool.hpp | 20 +- .../kth/blockchain/populate/populate_base.hpp | 19 +- .../blockchain/populate/populate_block.hpp | 19 +- .../populate/populate_chain_state.hpp | 8 +- .../populate/populate_transaction.hpp | 15 +- .../blockchain/validate/validate_block.hpp | 50 +- .../blockchain/validate/validate_header.hpp | 101 + .../validate/validate_transaction.hpp | 33 +- src/blockchain/src/interface/block_chain.cpp | 2071 +++++------- src/blockchain/src/pools/block_organizer.cpp | 326 +- src/blockchain/src/pools/header_organizer.cpp | 312 ++ .../src/pools/transaction_organizer.cpp | 251 +- src/blockchain/src/pools/transaction_pool.cpp | 16 +- src/blockchain/src/populate/populate_base.cpp | 44 +- .../src/populate/populate_block.cpp | 82 +- .../src/populate/populate_chain_state.cpp | 61 +- .../src/populate/populate_transaction.cpp | 55 +- .../src/validate/validate_block.cpp | 237 +- .../src/validate/validate_header.cpp | 128 + .../src/validate/validate_transaction.cpp | 96 +- src/c-api/conanfile.py | 156 - src/c-api/console/main.cpp | 8 +- src/c-api/console/print_headers.cpp | 8 +- .../include/kth/capi/chain/chain_other.h | 4 +- src/c-api/include/kth/capi/conversions.hpp | 2 +- src/c-api/include/kth/capi/primitives.h | 2 +- src/c-api/src/chain/chain_async.cpp | 23 +- src/c-api/src/chain/chain_other.cpp | 154 +- src/c-api/src/chain/chain_sync.cpp | 6 +- src/c-api/src/chain/mempool_transaction.cpp | 2 +- .../src/chain/mempool_transaction_list.cpp | 2 +- src/c-api/src/node.cpp | 2 +- src/consensus/conanfile.py | 131 - src/database/conanfile.py | 133 - .../include/kth/database/data_base.hpp | 73 +- .../kth/database/databases/block_database.ipp | 62 +- .../database/databases/header_abla_entry.hpp | 26 + .../database/databases/header_database.ipp | 187 +- .../database/databases/history_database.ipp | 23 +- .../database/databases/internal_database.hpp | 79 +- .../database/databases/internal_database.ipp | 400 ++- .../kth/database/databases/property_code.hpp | 2 + .../kth/database/databases/reorg_database.ipp | 38 +- .../kth/database/databases/spend_database.ipp | 15 +- .../databases/transaction_database.ipp | 10 +- .../transaction_unconfirmed_database.ipp | 18 +- .../include/kth/database/settings.hpp | 4 + src/database/src/data_base.cpp | 285 +- .../src/databases/header_abla_entry.cpp | 24 + src/database/src/settings.cpp | 1 + src/database/test/data_base.cpp | 38 +- src/domain/CMakeLists.txt | 20 +- src/domain/conanfile.py | 124 - src/infrastructure/CMakeLists.txt | 42 +- src/infrastructure/conanfile.py | 186 -- .../include/kth/infrastructure.hpp | 26 +- .../impl/utility/resubscriber.ipp | 13 +- .../impl/utility/subscriber.ipp | 13 +- .../{ => deprecated}/utility/delegates.hpp | 12 +- .../deprecated}/utility/dispatcher.cpp | 15 +- .../{ => deprecated}/utility/dispatcher.hpp | 29 +- .../{ => deprecated}/utility/resubscriber.hpp | 15 +- .../deprecated}/utility/sequencer.cpp | 12 +- .../{ => deprecated}/utility/sequencer.hpp | 10 + .../{ => deprecated}/utility/subscriber.hpp | 15 +- .../{ => deprecated}/utility/synchronizer.hpp | 10 + .../deprecated/utility/work.cpp | 31 + .../{ => deprecated}/utility/work.hpp | 12 +- .../kth/infrastructure/display_mode.hpp | 47 + .../include/kth/infrastructure/handlers.hpp | 6 + .../kth/infrastructure/log/statsd_sink.hpp | 1 - .../message/network_address.hpp | 1 + .../infrastructure/utility/broadcaster.hpp | 174 + .../kth/infrastructure/utility/deadline.hpp | 3 - .../infrastructure/utility/system_memory.hpp | 51 + .../kth/infrastructure/utility/threadpool.hpp | 17 +- src/infrastructure/src/log/sink.cpp | 4 +- src/infrastructure/src/log/statsd_sink.cpp | 1 - .../src/message/network_address.cpp | 118 + src/infrastructure/src/utility/deadline.cpp | 1 - src/infrastructure/src/utility/socket.cpp | 1 - .../src/utility/system_memory.cpp | 207 ++ src/infrastructure/src/utility/work.cpp | 22 - .../test/utility/threadpool.cpp | 1 + src/network/CMakeLists.txt | 126 +- src/network/conanfile.py | 108 - src/network/{src => deprecated}/acceptor.cpp | 10 + .../kth/network => deprecated}/acceptor.hpp | 10 + src/network/{src => deprecated}/channel.cpp | 12 +- .../kth/network => deprecated}/channel.hpp | 10 + src/network/{src => deprecated}/connector.cpp | 10 + .../kth/network => deprecated}/connector.hpp | 10 + .../message_subscriber.cpp | 10 + .../message_subscriber.hpp | 10 + src/network/{src => deprecated}/p2p.cpp | 31 +- .../kth/network => deprecated}/p2p.hpp | 24 +- .../protocols/protocol.cpp | 10 + .../protocols/protocol.hpp | 10 + .../protocols/protocol_address_31402.cpp | 10 + .../protocols/protocol_address_31402.hpp | 10 + .../protocols/protocol_events.cpp | 10 + .../protocols/protocol_events.hpp | 10 + .../protocols/protocol_ping_31402.cpp | 10 + .../protocols/protocol_ping_31402.hpp | 10 + .../protocols/protocol_ping_60001.cpp | 12 +- .../protocols/protocol_ping_60001.hpp | 10 + .../protocols/protocol_reject_70002.cpp | 10 + .../protocols/protocol_reject_70002.hpp | 11 +- .../protocols/protocol_seed_31402.cpp | 12 +- .../protocols/protocol_seed_31402.hpp | 10 + .../protocols/protocol_timer.cpp | 10 + .../protocols/protocol_timer.hpp | 10 + .../protocols/protocol_version_31402.cpp | 10 + .../protocols/protocol_version_31402.hpp | 11 +- .../protocols/protocol_version_70002.cpp | 10 + .../protocols/protocol_version_70002.hpp | 10 + src/network/{src => deprecated}/proxy.cpp | 12 +- .../kth/network => deprecated}/proxy.hpp | 11 +- .../{src => deprecated}/sessions/session.cpp | 10 + .../sessions/session.hpp | 10 + .../sessions/session_batch.cpp | 12 +- .../sessions/session_batch.hpp | 10 + .../sessions/session_inbound.cpp | 12 +- .../sessions/session_inbound.hpp | 10 + .../sessions/session_manual.cpp | 12 +- .../sessions/session_manual.hpp | 10 + .../sessions/session_outbound.cpp | 12 +- .../sessions/session_outbound.hpp | 10 + .../sessions/session_seed.cpp | 12 +- .../sessions/session_seed.hpp | 11 +- src/network/include/kth/network.hpp | 57 +- .../include/kth/network/handlers/ping.hpp | 31 + .../include/kth/network/handlers/pong.hpp | 31 + src/network/include/kth/network/hosts.hpp | 90 +- src/network/include/kth/network/p2p_node.hpp | 121 +- .../include/kth/network/peer_session.hpp | 40 +- .../include/kth/network/protocols_coro.hpp | 255 +- src/network/src/handlers/ping.cpp | 29 + src/network/src/handlers/pong.cpp | 21 + src/network/src/hosts.cpp | 366 +- src/network/src/p2p_node.cpp | 382 ++- src/network/src/peer_session.cpp | 43 +- src/network/src/protocols_coro.cpp | 421 ++- src/node-exe/CMakeLists.txt | 15 +- src/node-exe/conanfile.py | 141 - src/node-exe/src/main.cpp | 101 +- src/node-exe/src/tui_dashboard.cpp | 1139 +++++++ src/node-exe/src/tui_dashboard.hpp | 195 ++ src/node-exe/src/tui_dashboard_v1.cpp | 299 ++ src/node-exe/src/tui_dashboard_v1.hpp | 113 + src/node/CMakeLists.txt | 38 +- src/node/conanfile.py | 131 - src/node/include/kth/node.hpp | 19 +- .../include/kth/node/executor/executor.hpp | 26 +- src/node/include/kth/node/full_node.hpp | 564 +--- .../kth/node/protocols/protocol_block_in.hpp | 91 - .../kth/node/protocols/protocol_block_out.hpp | 67 - .../node/protocols/protocol_block_sync.hpp | 43 - .../protocol_double_spend_proof_in.hpp | 45 - .../protocol_double_spend_proof_out.hpp | 47 - .../node/protocols/protocol_header_sync.hpp | 52 - .../protocols/protocol_transaction_in.hpp | 49 - .../protocols/protocol_transaction_out.hpp | 52 - .../include/kth/node/sessions/session.hpp | 40 - .../kth/node/sessions/session_block_sync.hpp | 71 - .../kth/node/sessions/session_header_sync.hpp | 72 - .../kth/node/sessions/session_inbound.hpp | 40 - .../kth/node/sessions/session_manual.hpp | 37 - .../kth/node/sessions/session_outbound.hpp | 37 - src/node/include/kth/node/settings.hpp | 4 + src/node/include/kth/node/sync_session.hpp | 147 + .../include/kth/node/utility/reservation.hpp | 3 +- .../include/kth/node/utility/reservations.hpp | 4 +- src/node/src/executor/executor.cpp | 152 +- src/node/src/full_node.cpp | 751 ++--- src/node/src/parser.cpp | 30 + src/node/src/protocols/protocol_block_in.cpp | 819 ----- src/node/src/protocols/protocol_block_out.cpp | 544 --- .../src/protocols/protocol_block_sync.cpp | 146 - .../protocol_double_spend_proof_in.cpp | 147 - .../protocol_double_spend_proof_out.cpp | 183 - .../src/protocols/protocol_header_sync.cpp | 144 - .../src/protocols/protocol_transaction_in.cpp | 228 -- .../protocols/protocol_transaction_out.cpp | 257 -- src/node/src/sessions/session_block_sync.cpp | 223 -- src/node/src/sessions/session_header_sync.cpp | 206 -- src/node/src/sessions/session_inbound.cpp | 56 - src/node/src/sessions/session_manual.cpp | 54 - src/node/src/sessions/session_outbound.cpp | 54 - src/node/src/sync_session.cpp | 513 +++ src/node/src/utility/reservations.cpp | 2 +- src/node/test/utility.hpp | 2 +- 208 files changed, 12705 insertions(+), 9589 deletions(-) create mode 100644 doc/asio.md create mode 100644 doc/coroutine-migration-status.md delete mode 100644 src/blockchain/conanfile.py delete mode 100644 src/blockchain/include/kth/blockchain/interface/fast_chain.hpp delete mode 100644 src/blockchain/include/kth/blockchain/interface/safe_chain.hpp create mode 100644 src/blockchain/include/kth/blockchain/pools/header_organizer.hpp create mode 100644 src/blockchain/include/kth/blockchain/validate/validate_header.hpp create mode 100644 src/blockchain/src/pools/header_organizer.cpp create mode 100644 src/blockchain/src/validate/validate_header.cpp delete mode 100644 src/c-api/conanfile.py delete mode 100644 src/consensus/conanfile.py delete mode 100644 src/database/conanfile.py delete mode 100644 src/domain/conanfile.py delete mode 100644 src/infrastructure/conanfile.py rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/impl/utility/resubscriber.ipp (91%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/impl/utility/subscriber.ipp (87%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/delegates.hpp (75%) rename src/infrastructure/{src => include/kth/infrastructure/deprecated}/utility/dispatcher.cpp (59%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/dispatcher.hpp (90%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/resubscriber.hpp (72%) rename src/infrastructure/{src => include/kth/infrastructure/deprecated}/utility/sequencer.cpp (73%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/sequencer.hpp (66%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/subscriber.hpp (69%) rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/synchronizer.hpp (89%) create mode 100644 src/infrastructure/include/kth/infrastructure/deprecated/utility/work.cpp rename src/infrastructure/include/kth/infrastructure/{ => deprecated}/utility/work.hpp (84%) create mode 100644 src/infrastructure/include/kth/infrastructure/display_mode.hpp create mode 100644 src/infrastructure/include/kth/infrastructure/utility/broadcaster.hpp create mode 100644 src/infrastructure/include/kth/infrastructure/utility/system_memory.hpp create mode 100644 src/infrastructure/src/utility/system_memory.cpp delete mode 100644 src/infrastructure/src/utility/work.cpp delete mode 100644 src/network/conanfile.py rename src/network/{src => deprecated}/acceptor.cpp (88%) rename src/network/{include/kth/network => deprecated}/acceptor.hpp (75%) rename src/network/{src => deprecated}/channel.cpp (85%) rename src/network/{include/kth/network => deprecated}/channel.hpp (76%) rename src/network/{src => deprecated}/connector.cpp (90%) rename src/network/{include/kth/network => deprecated}/connector.hpp (79%) rename src/network/{src => deprecated}/message_subscriber.cpp (93%) rename src/network/{include/kth/network => deprecated}/message_subscriber.hpp (93%) rename src/network/{src => deprecated}/p2p.cpp (92%) rename src/network/{include/kth/network => deprecated}/p2p.hpp (90%) rename src/network/{src => deprecated}/protocols/protocol.cpp (74%) rename src/network/{include/kth/network => deprecated}/protocols/protocol.hpp (88%) rename src/network/{src => deprecated}/protocols/protocol_address_31402.cpp (86%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_address_31402.hpp (72%) rename src/network/{src => deprecated}/protocols/protocol_events.cpp (79%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_events.hpp (77%) rename src/network/{src => deprecated}/protocols/protocol_ping_31402.cpp (75%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_ping_31402.hpp (69%) rename src/network/{src => deprecated}/protocols/protocol_ping_60001.cpp (82%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_ping_60001.hpp (72%) rename src/network/{src => deprecated}/protocols/protocol_reject_70002.cpp (78%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_reject_70002.hpp (66%) rename src/network/{src => deprecated}/protocols/protocol_seed_31402.cpp (85%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_seed_31402.hpp (75%) rename src/network/{src => deprecated}/protocols/protocol_timer.cpp (77%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_timer.hpp (75%) rename src/network/{src => deprecated}/protocols/protocol_version_31402.cpp (93%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_version_31402.hpp (81%) rename src/network/{src => deprecated}/protocols/protocol_version_70002.cpp (88%) rename src/network/{include/kth/network => deprecated}/protocols/protocol_version_70002.hpp (80%) rename src/network/{src => deprecated}/proxy.cpp (93%) rename src/network/{include/kth/network => deprecated}/proxy.hpp (87%) rename src/network/{src => deprecated}/sessions/session.cpp (92%) rename src/network/{include/kth/network => deprecated}/sessions/session.hpp (92%) rename src/network/{src => deprecated}/sessions/session_batch.cpp (82%) rename src/network/{include/kth/network => deprecated}/sessions/session_batch.hpp (68%) rename src/network/{src => deprecated}/sessions/session_inbound.cpp (90%) rename src/network/{include/kth/network => deprecated}/sessions/session_inbound.hpp (75%) rename src/network/{src => deprecated}/sessions/session_manual.cpp (90%) rename src/network/{include/kth/network => deprecated}/sessions/session_manual.hpp (78%) rename src/network/{src => deprecated}/sessions/session_outbound.cpp (90%) rename src/network/{include/kth/network => deprecated}/sessions/session_outbound.hpp (76%) rename src/network/{src => deprecated}/sessions/session_seed.cpp (91%) rename src/network/{include/kth/network => deprecated}/sessions/session_seed.hpp (76%) create mode 100644 src/network/include/kth/network/handlers/ping.hpp create mode 100644 src/network/include/kth/network/handlers/pong.hpp create mode 100644 src/network/src/handlers/ping.cpp create mode 100644 src/network/src/handlers/pong.cpp delete mode 100644 src/node-exe/conanfile.py create mode 100644 src/node-exe/src/tui_dashboard.cpp create mode 100644 src/node-exe/src/tui_dashboard.hpp create mode 100644 src/node-exe/src/tui_dashboard_v1.cpp create mode 100644 src/node-exe/src/tui_dashboard_v1.hpp delete mode 100644 src/node/conanfile.py delete mode 100644 src/node/include/kth/node/protocols/protocol_block_in.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_block_out.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_block_sync.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_double_spend_proof_in.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_double_spend_proof_out.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_header_sync.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_transaction_in.hpp delete mode 100644 src/node/include/kth/node/protocols/protocol_transaction_out.hpp delete mode 100644 src/node/include/kth/node/sessions/session.hpp delete mode 100644 src/node/include/kth/node/sessions/session_block_sync.hpp delete mode 100644 src/node/include/kth/node/sessions/session_header_sync.hpp delete mode 100644 src/node/include/kth/node/sessions/session_inbound.hpp delete mode 100644 src/node/include/kth/node/sessions/session_manual.hpp delete mode 100644 src/node/include/kth/node/sessions/session_outbound.hpp create mode 100644 src/node/include/kth/node/sync_session.hpp delete mode 100644 src/node/src/protocols/protocol_block_in.cpp delete mode 100644 src/node/src/protocols/protocol_block_out.cpp delete mode 100644 src/node/src/protocols/protocol_block_sync.cpp delete mode 100644 src/node/src/protocols/protocol_double_spend_proof_in.cpp delete mode 100644 src/node/src/protocols/protocol_double_spend_proof_out.cpp delete mode 100644 src/node/src/protocols/protocol_header_sync.cpp delete mode 100644 src/node/src/protocols/protocol_transaction_in.cpp delete mode 100644 src/node/src/protocols/protocol_transaction_out.cpp delete mode 100644 src/node/src/sessions/session_block_sync.cpp delete mode 100644 src/node/src/sessions/session_header_sync.cpp delete mode 100644 src/node/src/sessions/session_inbound.cpp delete mode 100644 src/node/src/sessions/session_manual.cpp delete mode 100644 src/node/src/sessions/session_outbound.cpp create mode 100644 src/node/src/sync_session.cpp diff --git a/.gitignore b/.gitignore index 580cf1e2..34366d87 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ build-asan/ test_runner/ doc/release-notes/*.backup src/domain/CMakeLists.txt +bchn/ +/bitcoin-core/ *.mdb *.log banlist.dat diff --git a/CMakeLists.txt b/CMakeLists.txt index 764790d8..bc133596 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,14 @@ if (KTH_ASIO_STANDALONE) add_definitions(-DASIO_STANDALONE) endif() +# jemalloc support +option(KTH_WITH_JEMALLOC "Use jemalloc for memory allocation" OFF) +if (KTH_WITH_JEMALLOC) + find_package(jemalloc REQUIRED) + add_definitions(-DKTH_WITH_JEMALLOC) + message(STATUS "Knuth: jemalloc enabled") +endif() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/ci_utils/cmake) include(KnuthTools) diff --git a/conan.lock b/conan.lock index b5a9f302..f0781162 100644 --- a/conan.lock +++ b/conan.lock @@ -11,6 +11,7 @@ "libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1751603408.655", "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1725632951.012", "gmp/6.3.0#187de23af494e24e69bf9dfc1966a60d%1762775034.77", + "ftxui/6.1.9#053f78ab577d2d787fce0cd2e72bfa69%1748517521.121", "fmt/12.0.0#dc7de7f3968e5d6b377f27b7d0f33916%1758262922.745", "ctre/3.10.0#3f970a74e5cc3ba1a8ccb8e7f513062f%1755247138.192", "catch2/3.11.0#a560b55882ff2deb1f4bafad832a1b98%1762775012.454", diff --git a/conanfile.py b/conanfile.py index 260024b8..0d1950b3 100644 --- a/conanfile.py +++ b/conanfile.py @@ -71,6 +71,7 @@ class KthRecipe(KnuthConanFileV2): "with_icu": [True, False], "with_png": [True, False], "with_qrencode": [True, False], + "with_jemalloc": [True, False], "asio_standalone": [True, False], # secp256k1 options @@ -111,6 +112,14 @@ class KthRecipe(KnuthConanFileV2): "with_icu": False, "with_png": False, "with_qrencode": False, + # WARNING: jemalloc causes crashes with LMDB (mdb_env_close/mdb_dbi_close segfaults). + # LMDB uses mmap extensively which conflicts with jemalloc's memory management. + # Potential solutions if jemalloc is needed: + # 1. Run with MALLOC_CONF="retain:true" (less aggressive munmap) + # 2. Use MDB_WRITEMAP flag in LMDB (writes directly to mmap, bypasses malloc) + # 3. Compile LMDB separately without jemalloc linkage + # For now, keep disabled until a proper solution is implemented. + "with_jemalloc": False, "asio_standalone": True, # secp256k1 options @@ -163,6 +172,8 @@ def requirements(self): self.requires("ctre/3.10.0", transitive_headers=True, transitive_libs=True) self.requires("tiny-aes-c/1.0.0", transitive_headers=True, transitive_libs=True) + self.requires("ftxui/6.1.9", transitive_headers=True, transitive_libs=True) + # simdutf for SIMD-optimized base64 encoding (not available for WebAssembly) if self.settings.os != "Emscripten": self.requires("simdutf/7.1.0", transitive_headers=True, transitive_libs=True) @@ -173,6 +184,10 @@ def requirements(self): if self.options.with_qrencode: self.requires("libqrencode/4.1.1", transitive_headers=True, transitive_libs=True) + if self.options.with_jemalloc: + # https://jasone.github.io/2025/06/12/jemalloc-postmortem/ + self.requires("jemalloc/5.3.0", transitive_headers=True, transitive_libs=True) + if self.options.asio_standalone: self.requires("asio/1.36.0", transitive_headers=True, transitive_libs=True) @@ -250,6 +265,7 @@ def generate(self): tc.variables["WITH_ICU"] = option_on_off(self.options.with_icu) tc.variables["KTH_WITH_PNG"] = option_on_off(self.options.with_png) tc.variables["KTH_WITH_QRENCODE"] = option_on_off(self.options.with_qrencode) + tc.variables["KTH_WITH_JEMALLOC"] = option_on_off(self.options.with_jemalloc) tc.variables["KTH_ASIO_STANDALONE"] = option_on_off(self.options.asio_standalone) # Secp256k1 -------------------------------------------- @@ -359,6 +375,8 @@ def package_info(self): infrastructure_defines.append("KTH_WITH_PNG") if self.options.with_qrencode: infrastructure_defines.append("KTH_WITH_QRENCODE") + if self.options.with_jemalloc: + infrastructure_defines.append("KTH_WITH_JEMALLOC") self.cpp_info.components["infrastructure"].defines = infrastructure_defines # Infrastructure core dependencies: secp256k1, boost, fmt, ctre, spdlog, simdutf (non-wasm) self.cpp_info.components["infrastructure"].requires = [ @@ -379,8 +397,11 @@ def package_info(self): # Add asio when using standalone mode if self.options.asio_standalone: self.cpp_info.components["infrastructure"].requires.append("asio::asio") - - + # Add jemalloc when enabled + if self.options.with_jemalloc: + self.cpp_info.components["infrastructure"].requires.append("jemalloc::jemalloc") + + # Domain models and business logic self.cpp_info.components["domain"].libs = ["domain"] self.cpp_info.components["domain"].names["cmake_find_package"] = "domain" diff --git a/doc/asio.md b/doc/asio.md new file mode 100644 index 00000000..81ed16e0 --- /dev/null +++ b/doc/asio.md @@ -0,0 +1,2936 @@ +# PLAN DE MIGRACIÓN A ASIO MODERNO CON COROUTINES + +## Diagramas de Arquitectura + +### Arquitectura Actual (Callback-based) + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ FULL_NODE │ +│ (src/node/) │ +└──────────────────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ P2P │ +│ (src/network/p2p.hpp) │ +│ │ +│ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │ +│ │ pending_connect │ │ pending_handshake│ │ pending_close │ │ +│ │ (connectors) │ │ (channels) │ │ (established channels) │ │ +│ └─────────────────┘ └──────────────────┘ └──────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────────────┐ │ +│ │ threadpool + dispatcher │ │ +│ └─────────────────────────────────────────────────────────────────────┘ │ +└──────────────────────────────────┬──────────────────────────────────────────┘ + │ + ┌──────────────────────────┼──────────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌────────────────────┐ +│ session_seed │ │session_inbound│ │ session_outbound │ +│ │ │ │ │ │ +│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌──────────────┐ │ +│ │ connector │ │ │ │ acceptor │ │ │ │session_batch │ │ +│ └─────┬─────┘ │ │ └─────┬─────┘ │ │ │ │ │ +│ │ │ │ │ │ │ │ ┌──────────┐ │ │ +│ ▼ │ │ ▼ │ │ │ │connector │ │ │ +│ ┌─────────┐ │ │ ┌─────────┐ │ │ │ └────┬─────┘ │ │ +│ │ channel │ │ │ │ channel │ │ │ │ ▼ │ │ +│ └────┬────┘ │ │ └────┬────┘ │ │ │ ┌─────────┐ │ │ +│ │ │ │ │ │ │ │ │ channel │ │ │ +└───────┼───────┘ └───────┼───────┘ │ │ └────┬────┘ │ │ + │ │ │ └──────┼──────┘ │ + │ │ └─────────┼─────────┘ + │ │ │ + └────────────────────────┴──────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ CHANNEL │ +│ (src/network/channel.hpp) │ +│ │ +│ ┌─────────────────────────────────────────────────────────────────────┐ │ +│ │ PROXY │ │ +│ │ (src/network/proxy.hpp) │ │ +│ │ │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │ +│ │ │ socket │ │ sequencer │ │ message_subscriber │ │ │ +│ │ │ (mutex) │ │ (write queue)│ │ (callbacks) │ │ │ +│ │ └──────────────┘ └──────────────┘ └──────────────────────┘ │ │ +│ │ │ │ +│ │ read_heading() ──► handle_read_heading() ──► read_payload() ──► │ │ +│ │ handle_read_payload() ──► dispatch to subscribers ──► loop │ │ +│ │ │ │ +│ └─────────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │ +│ │ deadline │ │ deadline │ │ nonce/version │ │ +│ │ (inactivity) │ │ (expiration) │ │ (peer metadata) │ │ +│ └──────────────┘ └──────────────┘ └──────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ PROTOCOLS │ +│ (src/network/protocols/) │ +│ │ +│ protocol (base) │ +│ ├── protocol_events │ +│ │ ├── protocol_timer │ +│ │ │ ├── protocol_version_31402 ──► protocol_version_70002 │ +│ │ │ ├── protocol_ping_31402 ──► protocol_ping_60001 │ +│ │ │ ├── protocol_address_31402 │ +│ │ │ └── protocol_seed_31402 │ +│ │ └── protocol_reject_70002 │ +│ │ +│ Usan macros: BIND1-7, SEND1-3, SUBSCRIBE2-3 │ +│ Callbacks encadenados: send() → handle_send() → subscribe() → ... │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### Arquitectura Nueva (Coroutine-based) - En Progreso + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ FULL_NODE │ +│ (src/node/) │ +└──────────────────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ P2P_NODE │ +│ (src/network/p2p_node.hpp) [FASE 6] │ +│ │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ asio::thread_pool │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────┐ ┌────────────────────────────────┐ │ +│ │ peer_manager │◄────────────►│ concurrent_channel │ │ +│ │ [FASE 4] ✓ │ │ [FASE 1] ✓ │ │ +│ └─────────┬──────────┘ └────────────────────────────────┘ │ +│ │ │ +└──────────────┼───────────────────────────────────────────────────────────────┘ + │ + ┌──────────┴──────────┐ + │ │ + ▼ ▼ +┌──────────┐ ┌───────────────┐ +│ Outbound │ │ Inbound │ +│ │ │ │ +│ co_await │ │ co_await │ +│ connect │ │ accept │ +│ [FASE 3] │ │ [FASE 3] │ +└────┬─────┘ └───────┬───────┘ + │ │ + └──────────┬───────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ PEER_SESSION │ +│ (src/network/peer_session.hpp) [FASE 2] ✓ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────────────┐ │ +│ │ asio::strand │ │ +│ │ (serializa acceso al socket) │ │ +│ └─────────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────────┐ ┌───────────────────┐ ┌──────────────────┐ │ +│ │ tcp::socket │ │ concurrent_channel │ │ steady_timer │ │ +│ │ │ │ (outbound_) │ │ (inactivity) │ │ +│ └───────────────────┘ └───────────────────┘ └──────────────────┘ │ +│ │ +│ co_await run() ───────────────────────────────────────────────────────► │ +│ │ │ +│ ├── co_await read_loop() ──► async_read(heading) ──► async_read(payload)│ +│ ├── co_await write_loop() ──► channel.receive() ──► async_write() │ +│ ├── co_await inactivity() ──► timer.wait() ──► cancel or timeout │ +│ └── co_await expiration() ──► timer.wait() ──► session expires │ +│ │ +│ Todas corren en paralelo con || operator, cancelación automática │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ PROTOCOLS (Coroutine-based) │ +│ (src/network/protocols/) [FASE 5] │ +│ │ +│ awaitable handshake() { │ +│ co_await send(version_msg); // Lineal, sin callbacks │ +│ auto ver = co_await receive(); │ +│ co_await send(verack_msg); │ +│ co_await receive(); │ +│ co_return success; │ +│ } │ +│ │ +│ Sin macros BIND, sin callback chains, código lineal y legible │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### Clases a Eliminar vs. Reemplazo + +``` +CLASES LEGACY (a eliminar) REEMPLAZO MODERNO +═══════════════════════════════════════════════════════════════════════════════ + +┌───────────────────────────┐ ┌───────────────────────────────────┐ +│ infrastructure/ │ │ │ +├───────────────────────────┤ │ │ +│ threadpool.hpp ────────────────► │ asio::thread_pool (built-in) │ +│ work.hpp ────────────────► │ co_await post(executor) │ +│ sequencer.hpp ────────────────► │ asio::strand (built-in) │ +│ dispatcher.hpp ────────────────► │ co_spawn + strand │ +│ synchronizer.hpp ────────────────► │ awaitable operators (|| &&) │ +│ subscriber.hpp ────────────────► │ concurrent_channel │ +│ resubscriber.hpp ────────────────► │ concurrent_channel + retry │ +│ delegates.hpp ────────────────► │ Lambdas o eliminado │ +│ deadline.hpp ────────────────► │ asio::steady_timer directo │ +│ socket.hpp (mutex) ────────────────► │ Socket en strand, sin mutex │ +└───────────────────────────┘ │ │ + └───────────────────────────────────┘ + +┌───────────────────────────┐ ┌───────────────────────────────────┐ +│ network/ │ │ │ +├───────────────────────────┤ │ │ +│ proxy.hpp ────────────────► │ peer_session (coroutine loops) │ +│ channel.hpp ────────────────► │ peer_session │ +│ connector.hpp ────────────────► │ async_connect() helper o inline │ +│ acceptor.hpp ────────────────► │ async_accept() helper o inline │ +│ pending.hpp ────────────────► │ std::unordered_map + strand │ +│ message_subscriber ────────────────► │ concurrent_channel │ +└───────────────────────────┘ │ │ + └───────────────────────────────────┘ +``` + +### Estado de la Migración + +``` +═══════════════════════════════════════════════════════════════════════════════ + ESTADO ACTUAL DE FASES +═══════════════════════════════════════════════════════════════════════════════ + +[✓] FASE 0: Preparación + └── C++23, standalone Asio 1.36, verificado + +[✓] FASE 1: Infraestructura Base + ├── concurrent_channel probado y documentado + ├── Lección aprendida: channel vs concurrent_channel + └── awaitable_helpers disponibles + +[✓] FASE 2: peer_session (PR #142) + ├── peer_session.hpp creado + ├── peer_session.cpp implementado + ├── Tests unitarios: 31 test cases, 91 assertions ✓ + └── Reemplaza: proxy + channel + +[✓] FASE 3: Connector/Acceptor → Helpers (PR #142) + ├── async_connect(): DNS + TCP connect con timeout + ├── async_accept(): acepta conexiones entrantes + ├── async_listen(): crea acceptor en puerto + └── Tests incluidos en peer_session tests + +[✓] FASE 4: Session Management (PR #144) + ├── peer_manager.hpp/cpp creado + ├── Reemplaza: pending/pending collections + ├── Usa asio::strand para serialización (sin mutex) + ├── Todas las operaciones son coroutines (asio::awaitable) + ├── broadcast(), for_each(), add/remove/find operations + └── Tests unitarios completos + +[~] FASE 5: Protocols con Coroutines (PARCIAL) + ├── ✅ protocols_coro.hpp creado + ├── ✅ perform_handshake() - versión/verack + ├── ✅ run_ping_pong() - keepalive + ├── ✅ request_addresses() / send_addresses() + ├── ❌ FALTA: Block sync (getblocks, inv, getdata, block) + ├── ❌ FALTA: Header sync (getheaders, headers) + ├── ❌ FALTA: Transaction relay (inv, getdata, tx, mempool) + └── ❌ FALTA: Double spend proofs (BCH específico) + +[✓] FASE 6: P2P Node Modernizado + ├── p2p_node.hpp/cpp creado + ├── full_node usa composición con p2p_node (HAS-A en lugar de IS-A) + └── Conexión básica funciona (handshake + ping/pong) + +[✓] FASE 7: Cleanup (COMPLETA - Red P2P funcional) + ├── ✅ node::sessions eliminados (inbound, outbound, manual, block_sync, header_sync) + ├── ✅ node::protocols eliminados (block_in/out, header_sync, tx_in/out, dsp_in/out) + ├── ✅ network::sessions COMENTADOS (session.cpp, session_*.cpp) + ├── ✅ network::protocols legacy COMENTADOS (protocol_*.cpp) + ├── ✅ network::core legacy COMENTADOS (p2p.cpp, proxy.cpp, channel.cpp, acceptor.cpp, connector.cpp, message_subscriber.cpp) + ├── ✅ test/p2p.cpp COMENTADO (TODO: migrar tests a p2p_node.cpp) + ├── ✅ VERIFICADO EN RED REAL: + │ ├── Seeding funciona (obtiene 1000+ addresses) + │ ├── Conexiones outbound funcionan + │ ├── Handshake completo (version/verack) + │ ├── Ping/pong funciona correctamente + │ └── Recepción de mensajes (inv, addr, getheaders, feefilter, etc.) + ├── ⏳ c-api comentado temporalmente (reactivar cuando termine cleanup) + └── ⏳ infrastructure legacy (sequencer, dispatcher, etc.) - pendiente + +[ ] FASE 8: Integration Tests + └── Tests de conexión real a la red (requiere nodo limpio) + +═══════════════════════════════════════════════════════════════════════════════ +``` + +--- + +Now I have a comprehensive view of the architecture. Let me provide you with a detailed analysis report. + + --- + Comprehensive Boost Asio Architecture Review + + Executive Summary + + The codebase implements a well-structured, layered async I/O architecture using Boost/standalone Asio. The fundamental design is + architecturally sound with no critical flaws, but there are several areas for improvement and modernization opportunities. + + --- + 1. Architecture Overview + + The architecture follows a layered design: + + ┌─────────────────────────────────────────────────────┐ + │ full_node │ + │ (src/node/full_node.hpp) │ + ├─────────────────────────────────────────────────────┤ + │ p2p │ + │ (src/network/p2p.hpp) │ + ├─────────────────────────────────────────────────────┤ + │ Sessions (inbound, outbound, manual, seed) │ + │ (src/network/sessions/) │ + ├─────────────────────────────────────────────────────┤ + │ Protocols (version, ping, address, reject, etc.) │ + │ (src/network/protocols/) │ + ├─────────────────────────────────────────────────────┤ + │ channel → proxy → socket │ + │ (src/network/channel.hpp, proxy.hpp) │ + ├─────────────────────────────────────────────────────┤ + │ Infrastructure (threadpool, work, dispatcher) │ + │ (src/infrastructure/utility/) │ + └─────────────────────────────────────────────────────┘ + + --- + 2. Key Components Analysis + + 2.1 Thread Pool & Work Management (threadpool.hpp, work.hpp) + + Strengths: + - Uses modern io_context and executor_work_guard pattern (post-Boost 1.66) + - Proper use of asio::post() for async dispatch + - Four dispatch patterns: bound(), concurrent(), ordered(), unordered() + + Issues Found: + - Issue #76 TODO at work.hpp:65-66: The code uses bind_executor but has a TODO to review behavioral differences with deprecated + wrap(). This should be validated. + + // work.hpp:65-67 + // TODO: Review bind_executor vs deprecated wrap() for behavioral differences + // See: https://github.com/k-nuth/kth-mono/issues/76 + ::asio::post(service_, ::asio::bind_executor(strand_, ...)); + + 2.2 Sequencer (sequencer.cpp) + + Strengths: + - Correct FIFO ordering for async operations + - Proper mutex-protected queue + - Clean lock/unlock API for sequential async chains + + Correct Pattern: + void sequencer::lock(action&& handler) { + { + unique_lock locker(mutex_); + if (executing_) { + actions_.push(std::move(handler)); + return; + } + executing_ = true; + } + ::asio::post(service_, std::move(handler)); + } + + 2.3 Proxy (proxy.hpp, proxy.cpp) + + Strengths: + - Good separation of read/write cycles + - Proper use of dispatch_.lock() for write serialization (prevents deadlocks) + - Atomic stopped_ flag for safe concurrent access + + Read Cycle (Correct): + read_heading() → handle_read_heading() → read_payload() → handle_read_payload() → loop + + Write Cycle (Correct): + send() → dispatch_.lock() → do_send() → async_write → handle_send() → dispatch_.unlock() + + 2.4 Synchronizer (synchronizer.hpp) + + Strengths: + - Clean join pattern for coordinating multiple async operations + - Three termination modes: on_error, on_success, on_count + - Thread-safe with upgrade_mutex + + Potential Issue: + // synchronizer.hpp:100-105 + mutex_->unlock_upgrade_and_lock(); + (*counter_) = count; + mutex_->unlock(); + The upgrade-to-exclusive pattern is correct but could potentially cause priority inversion under heavy contention. + + 2.5 Pending Collections (pending.hpp) + + Strengths: + - Thread-safe container for managing connections + - Proper use of upgrade_mutex for read-heavy operations + - Clean stop/close semantics + + --- + 3. Concurrency Analysis + + 3.1 Thread Safety Patterns Used + + | Pattern | Location | Status | + |---------------|--------------------------------------------------|-----------| + | Atomic flags | proxy::stopped_, channel::notify_, p2p::stopped_ | ✅ Correct | + | Upgrade mutex | acceptor, connector, pending, synchronizer | ✅ Correct | + | Strands | work::strand_ | ✅ Correct | + | Sequencer | Write operations in proxy | ✅ Correct | + + 3.2 Potential Race Conditions + + No critical races found, but some areas need attention: + + 1. channel.cpp:97 - Comment says "inherent races, requiring stranding by stop only": + // Timers (these are inherent races, requiring stranding by stop only). + void channel::start_expiration() { + if (proxy::stopped()) { return; } + expiration_->start(...); + } + This is a benign race - if stopped, the timer handler will return early. + + 2. acceptor.cpp:121 - TODO about accept thread: + // TODO: if the accept is invoked on a thread of the acceptor, as opposed + // to the thread of the socket, then this is unnecessary. + + --- + 4. Architecture Observations + + 4.1 Good Practices Found + + 1. enable_shared_from_base<> - Proper pattern for safe async callbacks with inheritance + 2. RAII assertions - Destructors assert proper cleanup (KTH_ASSERT_MSG) + 3. Consistent use of shared_ptr for async lifetime management + 4. Clear separation between connection management (pending_connect, pending_handshake, pending_close) + + 4.2 Areas for Improvement + + 1. Excessive callback chains - The current pattern uses deeply nested std::bind chains: + // Example from session.cpp + channel->start(BIND3(handle_starting, _1, channel, handle_started)); + This is hard to follow and error-prone. + + 2. Manual memory management with std::bind - Error-prone, could be simplified. + 3. Commented-out code - Several files have extensive commented code blocks (e.g., dispatcher.hpp:142-206). + 4. Macros for binding - BIND1-7, SEND1-3, SUBSCRIBE2-3 macros are fragile and hard to debug. + + --- + 5. Modernization Opportunities + + 5.1 Coroutine Migration Path (C++20) + + High Impact, Moderate Effort: + + The current callback-based design can be migrated to coroutines. Here's a comparison: + + Current Pattern (callback hell): + void connector::connect(std::string const& hostname, uint16_t port, connect_handler handler) { + mutex_.lock_upgrade(); + if (stopped()) { + mutex_.unlock_upgrade(); + dispatch_.concurrent(handler, error::service_stopped, nullptr); + return; + } + mutex_.unlock_upgrade_and_lock(); + resolver_.async_resolve(hostname, std::to_string(port), + std::bind(&connector::handle_resolve, shared_from_this(), _1, _2, handler)); + mutex_.unlock(); + } + + void connector::handle_resolve(boost_code const& ec, asio::results_type results, connect_handler handler) { + // ... more callbacks + } + + With C++20 Coroutines: + asio::awaitable connector::connect(std::string const& hostname, uint16_t port) { + auto guard = co_await mutex_.async_lock(); + if (stopped()) { + co_return nullptr; + } + + auto results = co_await resolver_.async_resolve(hostname, std::to_string(port), asio::use_awaitable); + auto socket = std::make_shared(pool_); + + // Timer race + using namespace asio::experimental::awaitable_operators; + auto result = co_await ( + async_connect(socket->get(), results, asio::use_awaitable) || + timer_->async_wait(asio::use_awaitable) + ); + + if (result.index() == 1) { // timer won + co_return nullptr; + } + + co_return std::make_shared(pool_, socket, settings_); + } + + Benefits: + - Eliminates callback chains + - Better error handling with exceptions + - Cleaner code flow + - Easier debugging + + 5.2 Replace std::bind with Lambdas + + Low Effort, Medium Impact: + + // Before + channel->start(std::bind(&channel::do_start, shared_from_base(), _1, handler)); + + // After + channel->start([self = shared_from_base(), handler](code const& ec) { + self->do_start(ec, handler); + }); + + 5.3 Use asio::cancellation_slot (Asio 1.21+) + + For cleaner timeout/cancellation handling instead of manual timer races: + + asio::cancellation_signal signal; + auto slot = signal.slot(); + async_connect(socket, endpoints, asio::bind_cancellation_slot(slot, handler)); + // Later: signal.emit(asio::cancellation_type::total); + + 5.4 Consider asio::deferred (Asio 1.22+) + + For composing async operations without immediate execution. + + --- + 6. Parallelization Opportunities + + 6.1 Current Parallelism + + - Good: Multiple connections handled concurrently via io_context::run() on multiple threads + - Good: concurrent() dispatch for truly parallel operations + - Good: Read operations on different channels are parallel + + 6.2 Potential Improvements + + 1. Message serialization: Currently synchronous in proxy::send(). Could be moved to a worker pool. + 2. Batch broadcast: The p2p::broadcast() function could use asio::parallel_group (C++14/Asio 1.22+): + template + void broadcast(Message const& message, channel_handler handle_channel, result_handler handle_complete) { + auto const channels = pending_close_.collection(); + // Could use parallel_group for better coordination + } + + 3. DNS resolution: Multiple async_resolve calls could run in parallel for seed nodes. + + --- + 7. Specific Issues to Address + + | Priority | File | Issue | + |----------|------------------------------|-------------------------------------------------| + | Medium | work.hpp:65-66 | TODO: Validate bind_executor vs wrap() behavior | + | Low | hosts.cpp:20 | TODO: Change to bimap hash table | + | Low | session.hpp:146 | TODO: Create session_timer base class | + | Low | protocol_reject_70002.cpp:39 | TODO: Mitigate log fill DOS | + + --- + 8. Recommendations Summary + + Immediate (No Breaking Changes): + + 1. ✅ Resolve Issue #76 (bind_executor vs wrap()) + 2. ✅ Replace std::bind with lambdas incrementally + 3. ✅ Remove commented-out code blocks + 4. ✅ Replace binding macros with templates/lambdas + + Medium Term (Incremental): + + 1. Add asio::cancellation_slot support for cleaner cancellation + 2. Consider moving to asio::deferred for composable operations + 3. Implement the session_timer base class (TODO noted in code) + + Long Term (Coroutines Migration): + + 1. Start with new protocols using asio::awaitable + 2. Create coroutine wrappers for existing APIs + 3. Gradually migrate critical paths (connection, handshake) + 4. Full migration once C++20 is baseline requirement + + --- + 9. Conclusion + + The architecture is fundamentally sound. The codebase uses correct Asio patterns and has proper thread safety. The main technical + debt is the callback-based design which, while correct, is harder to maintain than modern coroutine-based approaches. + + Migration to coroutines is highly recommended for long-term maintainability and would significantly simplify the code. The current + design does not have blocking architectural issues that would prevent this migration. + + Parallelization is already good for a P2P networking stack. The main bottleneck would be at the application layer (blockchain + processing), not the networking layer. + +⏺ La revisión completa está terminada. El reporte anterior cubre todos los aspectos que pediste: + + Resumen ejecutivo: + + 1. Arquitectura fundamentalmente sólida - No hay fallas arquitectónicas críticas. Los patrones de Asio están correctamente + implementados. + 2. Concurrencia bien manejada - Uso correcto de: + - atomic para flags + - upgrade_mutex para colecciones + - strand para serialización + - sequencer para operaciones secuenciales async + 3. No hay race conditions críticas - Algunas son benignas y están documentadas en comentarios. + 4. Oportunidades de modernización: + - Coroutines (C++20): El mayor beneficio sería migrar de callbacks a asio::awaitable. Esto simplificaría enormemente el código. + - Reemplazar std::bind con lambdas: Más legible y menos propenso a errores + - Usar asio::cancellation_slot: Para manejo más limpio de timeouts + 5. Paralelización ya es buena - El cuello de botella probablemente esté en blockchain, no en networking. + 6. Issue pendiente: El TODO en work.hpp:65-66 sobre bind_executor vs wrap() debería ser resuelto. + + ¿Querés que profundice en algún aspecto específico o que empecemos a planificar la migración a coroutines? + + +------ + + +-------------------------------------------------------------------------------------------------------------------- + +Ahora, yo lo que me temo es que como este es codigo viejo (hace poco hicimos el cambio de io_service a io_context pero el resto +quedo igual) +Se implementan muchas cosas manualmente + +Channels, Sessions, timers, threadpool, ... + +O sea... sería bueno saber cómo se haría todo esto de cero. +O sea, tiene un nodo que se conecta a la red P2P, si tuvieras que escribir todo el networking de 0 en C++23, cómo lo harías? + +⏺ Excelente pregunta. Voy a analizar cómo se haría el networking de cero con C++23 y Asio moderno, comparándolo con lo que tienen + actualmente. + + Networking P2P desde Cero con C++23 + + 1. Lo que ya no necesitarías implementar manualmente + + | Componente Actual | Reemplazo Moderno | + |-----------------------------|---------------------------------------------------------------| + | threadpool + work_guard | asio::thread_pool (built-in) | + | sequencer | asio::strand + coroutines | + | dispatcher (4 métodos) | co_spawn + strand | + | synchronizer | asio::experimental::parallel_group o when_all | + | pending collection | asio::experimental::channel o simplemente std::vector + mutex | + | deadline timer wrapper | asio::steady_timer + co_await directo | + | subscriber/resubscriber | asio::experimental::channel | + | Callback chains (std::bind) | Coroutines lineales | + | enable_shared_from_base | Sigue necesario, pero menos crítico con coroutines | + + 2. Arquitectura Moderna Propuesta + + ┌─────────────────────────────────────────────────────────────┐ + │ p2p_node │ + │ - asio::thread_pool │ + │ - asio::experimental::channel │ + ├─────────────────────────────────────────────────────────────┤ + │ peer_manager │ + │ - std::unordered_map │ + │ - asio::strand (para mutación del map) │ + ├─────────────────────────────────────────────────────────────┤ + │ peer_session │ + │ - asio::ip::tcp::socket │ + │ - asio::steady_timer (inactivity) │ + │ - asio::experimental::channel (outbound queue) │ + │ - Coroutine: read_loop(), write_loop() │ + ├─────────────────────────────────────────────────────────────┤ + │ protocols │ + │ - Coroutines que consumen/producen messages │ + └─────────────────────────────────────────────────────────────┘ + + 3. Código de Ejemplo - Implementación Moderna + + // ============================================================================ + // p2p_node.hpp - El nodo completo + // ============================================================================ + #pragma once + + #include + #include + #include + #include + #include + #include + + namespace kth::network { + + using asio::awaitable; + using asio::co_spawn; + using asio::detached; + using asio::use_awaitable; + + // ---------------------------------------------------------------------------- + // Tipos básicos + // ---------------------------------------------------------------------------- + using error = std::error_code; + using peer_id = uint64_t; + + struct peer_event { + enum class type { connected, disconnected, message_received }; + type event_type; + peer_id id; + std::vector data; + }; + + // ---------------------------------------------------------------------------- + // peer_session - Una conexión a un peer + // ---------------------------------------------------------------------------- + class peer_session : public std::enable_shared_from_this { + public: + using ptr = std::shared_ptr; + using message_channel = asio::experimental::channel)>; + + peer_session(asio::ip::tcp::socket socket, peer_id id) + : socket_(std::move(socket)) + , strand_(socket_.get_executor()) + , id_(id) + , outbound_(socket_.get_executor(), 64) // buffer 64 messages + , inactivity_timer_(socket_.get_executor()) + {} + + // Inicia las coroutines de lectura/escritura + awaitable run() { + using namespace asio::experimental::awaitable_operators; + + // Correr read_loop y write_loop en paralelo + // Si cualquiera termina (error o cierre), cancelar la otra + co_await (read_loop() && write_loop() && inactivity_loop()); + } + + // Enviar mensaje (thread-safe, non-blocking) + awaitable send(std::vector message) { + co_await outbound_.async_send(error{}, std::move(message), use_awaitable); + } + + void close() { + asio::post(strand_, [self = shared_from_this()] { + self->socket_.close(); + self->outbound_.close(); + }); + } + + peer_id id() const { return id_; } + + private: + awaitable read_loop() { + std::array buffer; + + while (socket_.is_open()) { + // Leer header (24 bytes en Bitcoin) + auto [ec, header_bytes] = co_await asio::async_read( + socket_, + asio::buffer(buffer.data(), 24), + asio::as_tuple(use_awaitable) + ); + + if (ec) co_return; + + // Parsear header, obtener payload size + auto payload_size = parse_header(buffer); + if (payload_size > max_message_size) co_return; + + // Leer payload + std::vector payload(payload_size); + auto [ec2, _] = co_await asio::async_read( + socket_, + asio::buffer(payload), + asio::as_tuple(use_awaitable) + ); + + if (ec2) co_return; + + // Reset inactivity timer + reset_inactivity(); + + // Procesar mensaje (dispatch a protocol handlers) + co_await process_message(std::move(payload)); + } + } + + awaitable write_loop() { + while (socket_.is_open()) { + // Esperar mensaje en la cola + auto [ec, message] = co_await outbound_.async_receive(asio::as_tuple(use_awaitable)); + + if (ec) co_return; + + // Escribir mensaje completo + auto [write_ec, _] = co_await asio::async_write( + socket_, + asio::buffer(message), + asio::as_tuple(use_awaitable) + ); + + if (write_ec) co_return; + } + } + + awaitable inactivity_loop() { + while (socket_.is_open()) { + inactivity_timer_.expires_after(std::chrono::minutes(10)); + + auto [ec] = co_await inactivity_timer_.async_wait(asio::as_tuple(use_awaitable)); + + if (ec == asio::error::operation_aborted) { + continue; // Timer fue reseteado + } + + // Timeout - cerrar conexión + socket_.close(); + co_return; + } + } + + void reset_inactivity() { + inactivity_timer_.cancel(); + } + + awaitable process_message(std::vector payload); + size_t parse_header(std::span header); + + static constexpr size_t max_message_size = 32 * 1024 * 1024; + + asio::ip::tcp::socket socket_; + asio::strand strand_; + peer_id id_; + message_channel outbound_; + asio::steady_timer inactivity_timer_; + }; + + // ---------------------------------------------------------------------------- + // peer_manager - Gestiona todas las conexiones + // ---------------------------------------------------------------------------- + class peer_manager { + public: + peer_manager(asio::any_io_executor exec) + : exec_(exec) + , strand_(exec) + {} + + awaitable add_peer(asio::ip::tcp::socket socket) { + auto id = next_id_++; + auto session = std::make_shared(std::move(socket), id); + + // Agregar al map (en el strand) + co_await asio::post(strand_, use_awaitable); + peers_[id] = session; + + // Iniciar la sesión + co_spawn(exec_, session->run(), [this, id](std::exception_ptr) { + // Cuando termina, remover del map + asio::post(strand_, [this, id] { peers_.erase(id); }); + }); + } + + // Broadcast a todos los peers + awaitable broadcast(std::vector message) { + // Copiar lista de peers (snapshot) + co_await asio::post(strand_, use_awaitable); + auto peers_copy = peers_; + + // Enviar a todos en paralelo + for (auto& [id, session] : peers_copy) { + co_spawn(exec_, session->send(message), detached); + } + } + + size_t connection_count() const { + return peers_.size(); + } + + private: + asio::any_io_executor exec_; + asio::strand strand_; + std::unordered_map peers_; + std::atomic next_id_{0}; + }; + + // ---------------------------------------------------------------------------- + // connector - Conexiones salientes + // ---------------------------------------------------------------------------- + class connector { + public: + connector(asio::any_io_executor exec, peer_manager& manager) + : exec_(exec) + , resolver_(exec) + , manager_(manager) + {} + + awaitable> connect( + std::string host, + uint16_t port, + std::chrono::seconds timeout = std::chrono::seconds{30} + ) { + using namespace asio::experimental::awaitable_operators; + + // Resolver DNS + auto [resolve_ec, endpoints] = co_await resolver_.async_resolve( + host, std::to_string(port), + asio::as_tuple(use_awaitable) + ); + + if (resolve_ec) { + co_return std::unexpected(resolve_ec); + } + + // Crear socket y timer + asio::ip::tcp::socket socket(exec_); + asio::steady_timer timer(exec_); + timer.expires_after(timeout); + + // Race: connect vs timeout + auto result = co_await ( + asio::async_connect(socket, endpoints, asio::as_tuple(use_awaitable)) || + timer.async_wait(asio::as_tuple(use_awaitable)) + ); + + if (result.index() == 1) { + // Timeout ganó + co_return std::unexpected(asio::error::timed_out); + } + + auto [connect_ec, endpoint] = std::get<0>(result); + if (connect_ec) { + co_return std::unexpected(connect_ec); + } + + // Éxito - agregar al manager + co_await manager_.add_peer(std::move(socket)); + co_return {}; + } + + private: + asio::any_io_executor exec_; + asio::ip::tcp::resolver resolver_; + peer_manager& manager_; + }; + + // ---------------------------------------------------------------------------- + // acceptor - Conexiones entrantes + // ---------------------------------------------------------------------------- + class acceptor { + public: + acceptor(asio::any_io_executor exec, peer_manager& manager, uint16_t port) + : acceptor_(exec, {asio::ip::tcp::v6(), port}) + , manager_(manager) + { + acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); + } + + awaitable run() { + while (acceptor_.is_open()) { + auto [ec, socket] = co_await acceptor_.async_accept(asio::as_tuple(use_awaitable)); + + if (ec) { + if (ec == asio::error::operation_aborted) co_return; + continue; // Retry on other errors + } + + co_await manager_.add_peer(std::move(socket)); + } + } + + void stop() { + acceptor_.close(); + } + + private: + asio::ip::tcp::acceptor acceptor_; + peer_manager& manager_; + }; + + // ---------------------------------------------------------------------------- + // p2p_node - El nodo completo + // ---------------------------------------------------------------------------- + class p2p_node { + public: + p2p_node(size_t thread_count = std::thread::hardware_concurrency()) + : pool_(thread_count) + , manager_(pool_.get_executor()) + , connector_(pool_.get_executor(), manager_) + {} + + void start(uint16_t listen_port) { + acceptor_ = std::make_unique(pool_.get_executor(), manager_, listen_port); + co_spawn(pool_, acceptor_->run(), detached); + } + + awaitable connect_to(std::string host, uint16_t port) { + auto result = co_await connector_.connect(host, port); + if (!result) { + // Log error: result.error() + } + } + + awaitable broadcast(std::vector message) { + co_await manager_.broadcast(std::move(message)); + } + + void stop() { + if (acceptor_) acceptor_->stop(); + pool_.stop(); + } + + void join() { + pool_.join(); + } + + size_t connection_count() const { + return manager_.connection_count(); + } + + private: + asio::thread_pool pool_; + peer_manager manager_; + connector connector_; + std::unique_ptr acceptor_; + }; + + } // namespace kth::network + + 4. Comparación de Complejidad + + | Aspecto | Código Actual | Código Moderno + | + |-----------------------------|----------------------------------------------------------------------------|---------------------- + -----------------------------------------| + | Líneas de código (estimado) | ~5000 | ~800 + | + | Clases auxiliares | 15+ (sequencer, dispatcher, work, pending, synchronizer, subscriber, etc.) | 5 (peer_session, + peer_manager, connector, acceptor, p2p_node) | + | Callback depth | 4-6 niveles | 0 (código lineal) + | + | Thread safety | Manual (mutexes everywhere) | Automática (strands + + channels) | + | Error handling | Error codes pasados en callbacks | std::expected + + excepciones naturales | + | Cancellation | Manual con stopped_ flags | Automática con + cancel() | + + 5. Qué Desaparece Completamente + + 1. threadpool.hpp/cpp → asio::thread_pool (2 líneas) + 2. work.hpp → No necesario, co_spawn maneja lifetime + 3. sequencer.hpp/cpp → strand + coroutines naturalmente secuenciales + 4. dispatcher.hpp → co_spawn + strand + 5. synchronizer.hpp → parallel_group o awaitable_operators + 6. pending.hpp/ipp → std::unordered_map simple + 7. subscriber.hpp/ipp → asio::experimental::channel + 8. resubscriber.hpp/ipp → asio::experimental::channel + 9. deadline.hpp/cpp → asio::steady_timer directo + 10. Todos los BIND macros → Lambdas o nada (código lineal) + 11. delegates.hpp → No necesario + + 6. Protocol Handlers con Coroutines + + // Antes (callback hell): + void protocol_version_31402::start(result_handler handler) { + send(version_message, &CLASS::handle_send_version, handler); + } + + void protocol_version_31402::handle_send_version(code const& ec, result_handler handler) { + if (ec) { handler(ec); return; } + subscribe(&CLASS::handle_receive_version, handler); + } + + void protocol_version_31402::handle_receive_version(code const& ec, version_const_ptr msg, result_handler handler) { + // ... más callbacks + } + + // Después (lineal): + awaitable> handshake_protocol(peer_session& peer) { + // 1. Enviar version + auto send_result = co_await peer.send(make_version_message()); + if (!send_result) co_return std::unexpected(send_result.error()); + + // 2. Recibir version + auto version_msg = co_await peer.receive(); + if (!version_msg) co_return std::unexpected(version_msg.error()); + + // 3. Enviar verack + co_await peer.send(make_verack_message()); + + // 4. Recibir verack + auto verack = co_await peer.receive(); + if (!verack) co_return std::unexpected(verack.error()); + + // 5. Retornar info del peer + co_return version_info{ + .version = version_msg->version, + .services = version_msg->services, + .user_agent = version_msg->user_agent + }; + } + + 7. Recomendación de Migración + + Fase 1: Infraestructura (sin romper nada) + ├── Agregar asio::thread_pool como alternativa + ├── Crear wrappers awaitable para operaciones existentes + └── Escribir nuevos protocolos con coroutines + + Fase 2: Peer Session + ├── Reescribir peer_session con coroutines + ├── Mantener API externa compatible + └── Eliminar sequencer interno + + Fase 3: Session Management + ├── Simplificar session_inbound/outbound + ├── Eliminar subscriber/resubscriber + └── Usar channels para eventos + + Fase 4: Cleanup + ├── Eliminar clases auxiliares no usadas + ├── Simplificar p2p a la nueva arquitectura + └── Eliminar macros BIND + + --- + En resumen: Con C++23 y Asio moderno, aproximadamente el 70-80% del código de infraestructura actual es innecesario. Las + coroutines eliminan la necesidad de casi todas las clases auxiliares de sincronización y dispatch. + + ¿Querés que empiece a diseñar un plan concreto de migración fase por fase? + + +--- + +# PLAN DE MIGRACIÓN A ASIO MODERNO CON COROUTINES + +## Resumen Ejecutivo + +**Objetivo**: Migrar de la arquitectura callback-based actual a coroutines C++23 con Asio moderno. + +**Alcance**: +- ~3,783 líneas en infrastructure/utility (objetivo: reducir 70%) +- ~6,450 líneas en network (objetivo: reducir 50%) +- Eliminar ~11 clases auxiliares innecesarias + +**Estrategia**: Migración incremental sin breaking changes, manteniendo backwards compatibility hasta fase final. + +--- + +## Dependencias Identificadas + +``` +synchronizer.hpp ← blockchain/populate, blockchain/validate, dispatcher.hpp +dispatcher.hpp ← subscriber.hpp, resubscriber.hpp, database/data_base.hpp +work.hpp ← dispatcher.hpp, delegates.hpp +sequencer.hpp ← work.hpp +subscriber.hpp ← network/message_subscriber +resubscriber.hpp ← blockchain/block_organizer, blockchain/transaction_organizer +pending.hpp ← network/p2p (pending_connect, pending_handshake, pending_close) +``` + +**Orden de migración recomendado** (de menos a más dependencias): +1. sequencer → 2. work → 3. synchronizer → 4. dispatcher → 5. subscriber/resubscriber → 6. pending + +--- + +## Clases Legacy a Eliminar/Modernizar + +Estas clases fueron escritas ~2011-2016 y ya no son necesarias con Asio moderno + coroutines: + +| Clase | Ubicación | Problema | Reemplazo Moderno | Fase | +|-------|-----------|----------|-------------------|------| +| `sequencer` | infrastructure/utility | Reimplementa `asio::strand` manualmente con mutex+queue | `asio::strand<>` nativo | Fase 3 | +| `work` | infrastructure/utility | Wrappers triviales sobre `asio::post()` | `co_await asio::post(executor, use_awaitable)` | Fase 3 | +| `deadline` | infrastructure/utility | Wrapper con mutex innecesario sobre `steady_timer` | `asio::steady_timer` + strand | Fase 2 | +| `socket` | infrastructure/utility | Mutex manual innecesario si se usa strand | Socket directo con strand | Fase 2 | +| `synchronizer` | infrastructure/utility | Contador con callbacks | `std::latch`/`std::barrier` o coroutine simple | Fase 3 | +| `dispatcher` | infrastructure/utility | Event dispatch con callbacks | `concurrent_channel` + coroutines | Fase 3 | +| `subscriber` | infrastructure/utility | Pub/sub con callbacks | `concurrent_channel` broadcast | Fase 4 | +| `resubscriber` | infrastructure/utility | subscriber + auto-reconnect | Channel + retry loop | Fase 4 | +| `pending` | network | Tracking de operaciones pendientes | Eliminado con coroutines (await implícito) | Fase 2 | +| `proxy` | network | Wrapper complejo de socket+channels | `peer_session` coroutine-based | Fase 2 | +| `channel` (network) | network | Message framing sobre socket | Integrado en `peer_session` | Fase 2 | + +### Análisis Detallado + +**`sequencer`** (sequencer.hpp/cpp): +```cpp +// ANTES (2011): Cola manual con mutex +class sequencer { + void lock(action&& handler); // encola + void unlock(); // desencola y ejecuta siguiente + std::queue actions_; + mutable shared_mutex mutex_; +}; + +// AHORA (2025): strand nativo +asio::strand strand(executor); +co_await asio::post(strand, asio::use_awaitable); // serializado automáticamente +``` + +**`work`** (work.hpp): +```cpp +// ANTES: Wrappers innecesarios +work.concurrent(handler, args...); // → asio::post(executor_, bind(...)) +work.ordered(handler, args...); // → asio::post(strand_, bind(...)) + +// AHORA: Uso directo +co_await asio::post(executor, asio::use_awaitable); +co_await asio::post(strand, asio::use_awaitable); +``` + +**`deadline`** (deadline.cpp): +```cpp +// ANTES: Mutex manual para thread-safety +class deadline { + void start(handler, duration); + void stop(); + mutable upgrade_mutex mutex_; // innecesario con strand +}; + +// AHORA: Timer directo en strand +asio::steady_timer timer(strand); +timer.expires_after(5s); +auto [ec] = co_await timer.async_wait(as_tuple(use_awaitable)); +``` + +**`socket`** (socket.cpp): +```cpp +// ANTES: Mutex para acceso al socket +class socket { + asio::socket& get(); // con lock + void stop(); // con lock + mutable shared_mutex mutex_; +}; + +// AHORA: Socket en strand, sin mutex +// El strand garantiza que solo un handler accede al socket a la vez +``` + +--- + +## FASE 0: Preparación (Pre-requisitos) + +### 0.1 Verificar soporte de compiladores +``` +Mínimos requeridos: +- GCC 12+ (coroutines estables) +- Clang 16+ (coroutines estables) +- MSVC 19.30+ (VS 2022 17.0+) +``` + +**Acción**: Actualizar CI/CD y documentar requisitos. + +### 0.2 Actualizar Asio +```cpp +// Verificar que tenemos Asio 1.22+ o Boost 1.80+ +// Necesario para: +// - asio::experimental::channel +// - asio::experimental::parallel_group +// - asio::awaitable_operators +``` + +**Acción**: Verificar versión actual y actualizar si es necesario. + +### 0.3 Crear feature flag +```cpp +// kth/infrastructure/config.hpp +#if __cplusplus >= 202002L && defined(__cpp_impl_coroutine) + #define KTH_USE_COROUTINES 1 +#else + #define KTH_USE_COROUTINES 0 +#endif +``` + +**Acción**: Agregar macro para conditional compilation durante migración. + +### 0.4 Tests de integración de coroutines +**Acción**: Crear un test mínimo que verifique que coroutines funcionan con la configuración actual. + +```cpp +// test/coroutine_smoke_test.cpp +#include +#include + +asio::awaitable test_coro() { + asio::steady_timer timer(co_await asio::this_coro::executor); + timer.expires_after(std::chrono::milliseconds(1)); + co_await timer.async_wait(asio::use_awaitable); + co_return 42; +} + +TEST(Coroutines, SmokeTest) { + asio::io_context ctx; + int result = 0; + asio::co_spawn(ctx, test_coro(), [&](std::exception_ptr, int r) { result = r; }); + ctx.run(); + EXPECT_EQ(result, 42); +} +``` + +--- + +## FASE 1: Infraestructura Base (Sin romper nada) + +### 1.1 Agregar asio::thread_pool como alternativa +**Archivo**: `src/infrastructure/include/kth/infrastructure/utility/thread_pool.hpp` (NUEVO) + +```cpp +#pragma once + +#include + +namespace kth { + +#if KTH_USE_COROUTINES + +// Nueva implementación minimalista +class thread_pool_modern { +public: + explicit thread_pool_modern(size_t threads = std::thread::hardware_concurrency()) + : pool_(threads) {} + + asio::any_io_executor get_executor() { + return pool_.get_executor(); + } + + void stop() { pool_.stop(); } + void join() { pool_.join(); } + +private: + asio::thread_pool pool_; +}; + +#endif + +// Alias condicional +#if KTH_USE_COROUTINES +using thread_pool_t = thread_pool_modern; +#else +using thread_pool_t = threadpool; // existing class +#endif + +} // namespace kth +``` + +**Tests**: Verificar que thread_pool_modern funciona igual que threadpool existente. + +### 1.2 Crear wrappers awaitable para operaciones existentes +**Archivo**: `src/infrastructure/include/kth/infrastructure/utility/awaitable_helpers.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +#include +#include + +namespace kth { + +using asio::awaitable; +using asio::use_awaitable; + +// Helper para convertir callbacks existentes a awaitables +template +awaitable> to_awaitable(auto async_op) { + // Implementación con asio::async_initiate +} + +// Timeout wrapper +template +awaitable> with_timeout( + awaitable op, + std::chrono::milliseconds timeout +) { + using namespace asio::experimental::awaitable_operators; + auto executor = co_await asio::this_coro::executor; + asio::steady_timer timer(executor); + timer.expires_after(timeout); + + auto result = co_await ( + std::move(op) || + timer.async_wait(use_awaitable) + ); + + if (result.index() == 1) { + co_return std::unexpected(error::channel_timeout); + } + co_return std::get<0>(std::move(result)); +} + +} // namespace kth + +#endif +``` + +### 1.3 Agregar channel para comunicación async +**Archivo**: `src/infrastructure/include/kth/infrastructure/utility/async_channel.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +#include +#include + +namespace kth { + +// ============================================================================= +// IMPORTANTE: Thread Safety de Channels +// ============================================================================= +// +// asio::experimental::channel: +// - Thread Safety: "Distinct objects: Safe. Shared objects: Unsafe." +// - Para uso en el MISMO strand/thread +// - Más eficiente (sin locks internos) +// - Usar cuando todas las coroutines corren en el mismo strand +// +// asio::experimental::concurrent_channel: +// - Thread Safety: Safe para acceso concurrente desde múltiples threads +// - Para uso desde DIFERENTES threads del pool +// - Tiene locks internos, ligero overhead +// - Usar cuando productores/consumidores corren en threads diferentes +// +// ============================================================================= + +// Channel para uso en el mismo strand (no thread-safe) +// Uso: Comunicación entre coroutines que corren en el mismo strand +// Ejemplo: Stages de procesamiento serializado, pipelines single-thread +template +using async_channel = asio::experimental::channel; + +// Channel thread-safe para uso desde múltiples threads +// Uso: Comunicación entre coroutines en diferentes threads del pool +// Ejemplo: Work queues, distribución de trabajo a múltiples workers +template +using concurrent_channel = asio::experimental::concurrent_channel; + +// Channel de eventos (sin datos, solo señalización) +using event_channel = async_channel<>; +using concurrent_event_channel = concurrent_channel<>; + +} // namespace kth + +#endif +``` + +### 1.4 Lecciones Aprendidas: Thread Safety de Channels + +Durante la implementación y testing de channels, descubrimos un problema importante de concurrencia: + +**El Problema**: +Un test con 5 productores concurrentes enviando valores al channel fallaba aleatoriamente. +Los valores se corrompían: esperábamos `sum=15` (1+2+3+4+5) pero obteníamos valores como 14, 11, 7. + +``` +FAIL: send_count=5 count=5 sum=14 + Received: 0 0 0 0 2 (esperado: 1 2 3 4 5 en cualquier orden) +``` + +**La Causa**: +`asio::experimental::channel` NO es thread-safe para acceso concurrente. +Documentación: "Distinct objects: Safe. Shared objects: Unsafe." +https://think-async.com/Asio/asio-1.36.0/doc/asio/reference/experimental__channel.html + +**La Solución**: +- Usar `concurrent_channel` para escenarios multi-threaded (múltiples productores/consumidores en diferentes threads) +- O usar un `strand` para serializar acceso a un `channel` regular + +**Guía de Uso en el Nodo**: + +| Escenario | Tipo de Channel | Ejemplo | +|-----------|-----------------|---------| +| Comunicación intra-peer | `async_channel` + strand | read_loop → write_loop en peer_session | +| Pipeline serializado | `async_channel` + strand | Stages de validación de bloques | +| Work queue multi-worker | `concurrent_channel` | Distribución de transacciones a validadores | +| Múltiples peers → procesador | `concurrent_channel` | Mensajes de red hacia procesador central | + +**Entregables Fase 1**: +- [x] `threadpool.hpp` con implementación usando `asio::thread_pool` +- [x] `awaitable_helpers.hpp` con utilities +- [x] `async_channel.hpp` con typedefs para `channel` y `concurrent_channel` +- [ ] Tests unitarios: + - [x] threadpool: stop/join behavior + - [ ] async_channel con strand (single-thread safe) + - [ ] concurrent_channel sin strand (multi-thread safe) +- [ ] Build exitoso con standalone Asio 1.36.0 + +--- + +## FASE 2: Proxy/Channel Modernizado + +### 2.1 Crear peer_session moderna (en paralelo a proxy/channel existente) +**Archivo**: `src/network/include/kth/network/peer_session.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +#include +#include + +namespace kth::network { + +class peer_session : public std::enable_shared_from_this { +public: + using ptr = std::shared_ptr; + using message_channel = async_channel>; + + peer_session(asio::ip::tcp::socket socket, settings const& settings); + + awaitable run(); + awaitable send(std::vector message); + void close(); + + // Compatibilidad con API existente + infrastructure::config::authority authority() const; + bool stopped() const; + +private: + awaitable read_loop(); + awaitable write_loop(); + awaitable inactivity_loop(); + + asio::ip::tcp::socket socket_; + asio::strand strand_; + message_channel outbound_; + asio::steady_timer inactivity_timer_; + std::atomic stopped_{false}; + settings const& settings_; +}; + +} // namespace kth::network + +#endif +``` + +### 2.2 Implementación de peer_session +**Archivo**: `src/network/src/peer_session.cpp` (NUEVO) + +```cpp +#if KTH_USE_COROUTINES + +#include +#include + +namespace kth::network { + +using namespace asio::experimental::awaitable_operators; + +peer_session::peer_session(asio::ip::tcp::socket socket, settings const& settings) + : socket_(std::move(socket)) + , strand_(socket_.get_executor()) + , outbound_(socket_.get_executor(), 64) + , inactivity_timer_(socket_.get_executor()) + , settings_(settings) +{} + +awaitable peer_session::run() { + // Las tres coroutines corren en paralelo + // Si cualquiera termina, las otras se cancelan automáticamente + co_await (read_loop() && write_loop() && inactivity_loop()); + + // Cleanup + stopped_ = true; + socket_.close(); + outbound_.close(); +} + +awaitable peer_session::read_loop() { + std::array header_buffer; + + while (!stopped_) { + // Leer header + auto [ec, n] = co_await asio::async_read( + socket_, + asio::buffer(header_buffer), + asio::as_tuple(use_awaitable) + ); + + if (ec) co_return; + + // Parse header para obtener payload size + auto const payload_size = parse_message_header(header_buffer); + if (payload_size > max_message_size) co_return; + + // Leer payload + std::vector payload(payload_size); + auto [ec2, _] = co_await asio::async_read( + socket_, + asio::buffer(payload), + asio::as_tuple(use_awaitable) + ); + + if (ec2) co_return; + + // Reset inactivity timer + inactivity_timer_.cancel(); + + // Procesar mensaje + co_await handle_message(header_buffer, std::move(payload)); + } +} + +awaitable peer_session::write_loop() { + while (!stopped_) { + auto [ec, message] = co_await outbound_.async_receive( + asio::as_tuple(use_awaitable) + ); + + if (ec) co_return; + + auto [write_ec, _] = co_await asio::async_write( + socket_, + asio::buffer(message), + asio::as_tuple(use_awaitable) + ); + + if (write_ec) co_return; + } +} + +awaitable peer_session::inactivity_loop() { + while (!stopped_) { + inactivity_timer_.expires_after(settings_.channel_inactivity()); + + auto [ec] = co_await inactivity_timer_.async_wait( + asio::as_tuple(use_awaitable) + ); + + if (ec == asio::error::operation_aborted) { + continue; // Timer was reset, continue waiting + } + + // Inactivity timeout + co_return; + } +} + +awaitable peer_session::send(std::vector message) { + co_await outbound_.async_send(std::error_code{}, std::move(message), use_awaitable); +} + +void peer_session::close() { + asio::post(strand_, [self = shared_from_this()] { + self->stopped_ = true; + self->socket_.close(); + self->outbound_.close(); + self->inactivity_timer_.cancel(); + }); +} + +} // namespace kth::network + +#endif +``` + +### 2.3 Adapter para usar peer_session donde se usaba channel +**Archivo**: `src/network/include/kth/network/channel_adapter.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +// Adapter que expone API compatible con channel existente +// pero usa peer_session internamente +class channel_adapter { +public: + using ptr = std::shared_ptr; + + channel_adapter(peer_session::ptr session); + + // API compatible con channel existente + template + void send(Message const& message, result_handler handler) { + auto data = serialize(message); + asio::co_spawn(session_->get_executor(), + session_->send(std::move(data)), + [handler](std::exception_ptr ep) { + handler(ep ? error::operation_failed : error::success); + }); + } + + void stop(code const& ec); + infrastructure::config::authority authority() const; + // ... otros métodos de compatibilidad + +private: + peer_session::ptr session_; +}; + +} // namespace kth::network + +#endif +``` + +**Entregables Fase 2**: +- [ ] `peer_session.hpp/cpp` implementado y testeado +- [ ] `channel_adapter.hpp` para compatibilidad +- [ ] Tests que comparan comportamiento peer_session vs channel existente +- [ ] Sin cambios a código existente todavía + +--- + +## FASE 3: Connector/Acceptor Modernizado + +### 3.1 Modern connector +**Archivo**: `src/network/include/kth/network/connector_coro.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +class connector_coro { +public: + connector_coro(asio::any_io_executor exec, settings const& settings); + + awaitable> connect( + std::string const& host, + uint16_t port + ); + + void stop(); + +private: + asio::any_io_executor exec_; + asio::ip::tcp::resolver resolver_; + settings const& settings_; + std::atomic stopped_{false}; +}; + +} // namespace kth::network + +#endif +``` + +### 3.2 Modern acceptor +**Archivo**: `src/network/include/kth/network/acceptor_coro.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +class acceptor_coro { +public: + acceptor_coro(asio::any_io_executor exec, settings const& settings); + + awaitable listen(uint16_t port); + awaitable> accept(); + void stop(); + +private: + asio::ip::tcp::acceptor acceptor_; + settings const& settings_; +}; + +} // namespace kth::network + +#endif +``` + +**Entregables Fase 3**: +- [ ] `connector_coro.hpp/cpp` implementado +- [ ] `acceptor_coro.hpp/cpp` implementado +- [ ] Tests de conexión/aceptación + +--- + +## FASE 4: Session Management Modernizado + +### 4.1 Peer manager (reemplaza session + pending collections) +**Archivo**: `src/network/include/kth/network/peer_manager.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +class peer_manager { +public: + peer_manager(asio::any_io_executor exec); + + awaitable add_peer(peer_session::ptr session); + void remove_peer(peer_id id); + + size_t connection_count() const; + bool connected(infrastructure::config::authority const& addr) const; + + // Broadcast + awaitable broadcast(std::vector message); + + // Iteration (thread-safe snapshot) + std::vector get_peers() const; + +private: + asio::any_io_executor exec_; + asio::strand strand_; + std::unordered_map peers_; + std::atomic next_id_{0}; + mutable std::shared_mutex mutex_; +}; + +} // namespace kth::network + +#endif +``` + +**Entregables Fase 4**: +- [x] `peer_manager.hpp/cpp` implementado (PR #144) +- [x] Elimina necesidad de `pending.hpp` para connections +- [x] Tests de gestión de peers + +--- + +## FASE 5: Protocols con Coroutines + +### Clases de Protocol Existentes + +Las siguientes clases implementan el protocolo Bitcoin sobre TCP. Actualmente usan callbacks y macros `BIND`. Serán migradas a coroutines en esta fase. + +| Clase | Archivo | Descripción | Dependencias | Complejidad | +|-------|---------|-------------|--------------|-------------| +| `protocol` | `protocols/protocol.hpp/cpp` | **Clase base** para todos los protocolos. Provee acceso a channel, timer, authority, versión, y métodos `send()` con callbacks. | `channel`, `timer` | Media | +| `protocol_events` | `protocols/protocol_events.hpp/cpp` | Base con eventos de start/stop. Extiende `protocol`. | `protocol` | Baja | +| `protocol_timer` | `protocols/protocol_timer.hpp/cpp` | Base con timer periódico. Extiende `protocol_events`. | `protocol_events`, `deadline` | Baja | +| `protocol_version_31402` | `protocols/protocol_version_31402.hpp/cpp` | **Handshake v1** (protocol version 31402). Envía/recibe `version` y `verack`. | `protocol_timer` | Alta | +| `protocol_version_70002` | `protocols/protocol_version_70002.hpp/cpp` | **Handshake v2** (protocol version 70002+). Añade relay flag y reject. | `protocol_version_31402` | Alta | +| `protocol_ping_31402` | `protocols/protocol_ping_31402.hpp/cpp` | **Ping básico** sin nonce. Responde a `ping` con `pong`. | `protocol_timer` | Baja | +| `protocol_ping_60001` | `protocols/protocol_ping_60001.hpp/cpp` | **Ping con nonce** (BIP 31). Mide latencia con nonce round-trip. | `protocol_ping_31402` | Media | +| `protocol_address_31402` | `protocols/protocol_address_31402.hpp/cpp` | **Intercambio de direcciones**. Envía/recibe `addr` y `getaddr`. | `protocol_timer` | Media | +| `protocol_seed_31402` | `protocols/protocol_seed_31402.hpp/cpp` | **Seeding inicial**. Obtiene direcciones de seed nodes. | `protocol_timer` | Media | +| `protocol_reject_70002` | `protocols/protocol_reject_70002.hpp/cpp` | **Manejo de reject** (BIP 61). Procesa mensajes de rechazo. | `protocol_events` | Baja | + +### Jerarquía de Herencia + +``` +protocol (base) +├── protocol_events +│ ├── protocol_timer +│ │ ├── protocol_version_31402 +│ │ │ └── protocol_version_70002 +│ │ ├── protocol_ping_31402 +│ │ │ └── protocol_ping_60001 +│ │ ├── protocol_address_31402 +│ │ └── protocol_seed_31402 +│ └── protocol_reject_70002 +``` + +### Estrategia de Migración de Protocols + +**Orden recomendado** (de menos a más dependencias): + +1. `protocol_coro` (nueva base con coroutines) +2. `protocol_events_coro` (eventos como channels) +3. `protocol_timer_coro` (timer con co_await) +4. `protocol_reject_coro` (simple, sin estado complejo) +5. `protocol_ping_31402_coro` y `protocol_ping_60001_coro` +6. `protocol_address_31402_coro` +7. `protocol_seed_31402_coro` +8. `protocol_version_31402_coro` y `protocol_version_70002_coro` (críticos para handshake) + +### 5.1 Protocol base con coroutines +**Archivo**: `src/network/include/kth/network/protocols/protocol_coro.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +// Base para protocolos con coroutines +class protocol_coro { +public: + protocol_coro(peer_session::ptr session); + + virtual awaitable run() = 0; + +protected: + // Helpers para enviar/recibir mensajes tipados + template + awaitable send(Message const& msg); + + template + awaitable> receive(); + + template + awaitable> receive_with_timeout( + std::chrono::milliseconds timeout + ); + + peer_session::ptr session_; +}; + +} // namespace kth::network + +#endif +``` + +### 5.2 Handshake protocol moderno +**Archivo**: `src/network/include/kth/network/protocols/protocol_version_coro.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +struct handshake_result { + uint32_t version; + uint64_t services; + std::string user_agent; +}; + +class protocol_version_coro : public protocol_coro { +public: + protocol_version_coro(peer_session::ptr session, settings const& settings); + + awaitable> run() override; + +private: + awaitable send_version(); + awaitable> receive_version(); + awaitable send_verack(); + awaitable receive_verack(); + + settings const& settings_; +}; + +// Implementación lineal y legible: +awaitable> protocol_version_coro::run() { + // 1. Enviar version + if (auto ec = co_await send_version(); ec) { + co_return std::unexpected(ec); + } + + // 2. Recibir version + auto version_result = co_await receive_version(); + if (!version_result) { + co_return std::unexpected(version_result.error()); + } + + // 3. Validar version + if (version_result->value < minimum_version) { + co_return std::unexpected(error::accept_failed); + } + + // 4. Enviar verack + if (auto ec = co_await send_verack(); ec) { + co_return std::unexpected(ec); + } + + // 5. Recibir verack (con timeout) + auto verack = co_await receive_with_timeout( + std::chrono::seconds{30} + ); + if (!verack) { + co_return std::unexpected(verack.error()); + } + + // 6. Éxito + co_return handshake_result{ + .version = version_result->value, + .services = version_result->services, + .user_agent = version_result->user_agent + }; +} + +} // namespace kth::network + +#endif +``` + +**Entregables Fase 5**: +- [x] `protocols_coro.hpp/cpp` - funciones libres con coroutines (PR #145) + - `wait_for_message()` y `wait_for_any_message()` helpers + - `perform_handshake()` para version/verack exchange + - `run_ping_pong()` para keepalive loop + - `request_addresses()` y `send_addresses()` para addr protocol +- [x] Tests para cada protocolo + +--- + +## FASE 6: P2P Node Modernizado + +### 6.1 p2p_node moderno +**Archivo**: `src/network/include/kth/network/p2p_node.hpp` (NUEVO) + +```cpp +#pragma once + +#if KTH_USE_COROUTINES + +namespace kth::network { + +class p2p_node { +public: + p2p_node(settings const& settings); + ~p2p_node(); + + // Lifecycle + awaitable start(); + void stop(); + void join(); + + // Connections + awaitable connect(std::string const& host, uint16_t port); + + // Broadcast + template + awaitable broadcast(Message const& msg); + + // Properties + size_t connection_count() const; + bool stopped() const; + settings const& network_settings() const; + + // Subscriptions (usando channels) + async_channel& connection_channel(); + event_channel& stop_channel(); + +private: + awaitable run_acceptor(); + awaitable run_outbound_sessions(); + awaitable run_seeding(); + + settings const& settings_; + asio::thread_pool pool_; + peer_manager manager_; + connector_coro connector_; + std::unique_ptr acceptor_; + + async_channel connection_events_; + event_channel stop_events_; + + std::atomic stopped_{true}; +}; + +} // namespace kth::network + +#endif +``` + +### 6.2 TODOs pendientes de p2p_node + +**`get_peers()` sync method**: El método `std::vector get_peers() const` actualmente retorna un vector vacío. Opciones: +1. **Eliminar el método**: Forzar a los usuarios a usar `peers().all()` (async) +2. **Implementar con run_sync**: Usar un helper para ejecutar el coroutine sincrónicamente (no recomendado, puede bloquear) +3. **Cache interno**: Mantener un snapshot actualizado en cada add/remove (overhead) + +**Recomendación**: Eliminar `get_peers()` sync y solo exponer `peers()` que da acceso a `peer_manager` con su método async `all()`. + +**Entregables Fase 6**: +- [x] `p2p_node.hpp/cpp` implementado +- [ ] Resolver `get_peers()` sync (eliminar o implementar) +- [ ] Funcionalidad equivalente a `p2p` existente +- [ ] Tests unitarios de p2p_node + +--- + +## FASE 7: Cleanup (Post-migración) + +### 7.1 Eliminar código legacy +Una vez que la migración está completa y validada en producción: + +```bash +# Archivos a eliminar: +src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp +src/infrastructure/src/utility/sequencer.cpp +src/infrastructure/include/kth/infrastructure/utility/work.hpp +src/infrastructure/src/utility/work.cpp +src/infrastructure/include/kth/infrastructure/utility/dispatcher.hpp +src/infrastructure/src/utility/dispatcher.cpp +src/infrastructure/include/kth/infrastructure/utility/synchronizer.hpp +src/infrastructure/include/kth/infrastructure/utility/subscriber.hpp +src/infrastructure/include/kth/infrastructure/impl/utility/subscriber.ipp +src/infrastructure/include/kth/infrastructure/utility/resubscriber.hpp +src/infrastructure/include/kth/infrastructure/impl/utility/resubscriber.ipp +src/infrastructure/include/kth/infrastructure/utility/delegates.hpp + +# Network legacy: +src/network/include/kth/network/proxy.hpp +src/network/src/proxy.cpp +src/network/include/kth/network/channel.hpp +src/network/src/channel.cpp +# ... etc +``` + +### 7.2 Renombrar p2p_node a p2p +Una vez que `p2p.hpp` y `p2p.cpp` legacy sean eliminados: +```bash +# Renombrar archivos: +mv src/network/include/kth/network/p2p_node.hpp src/network/include/kth/network/p2p.hpp +mv src/network/src/p2p_node.cpp src/network/src/p2p.cpp + +# Renombrar clase: +# p2p_node → p2p +# connection_result puede quedarse igual o moverse a su propio header +``` + +### 7.3 Actualizar includes en infrastructure.hpp +```cpp +// Remover: +// #include +// #include +// ... etc + +// Mantener: +#include +#include +#include +``` + +### 7.4 Eliminar macros BIND +```bash +# Buscar y eliminar: +grep -r "BIND[0-9]" src/ +grep -r "SEND[0-9]" src/ +grep -r "SUBSCRIBE[0-9]" src/ +``` + +**Entregables Fase 7**: +- [x] node::sessions eliminados +- [x] node::protocols eliminados +- [x] network::sessions COMENTADOS (listos para eliminar) +- [x] network::protocols legacy COMENTADOS (listos para eliminar) +- [x] network::core legacy COMENTADOS (p2p.cpp, proxy.cpp, channel.cpp, etc.) +- [x] test/p2p.cpp COMENTADO (TODO: migrar tests a p2p_node.cpp antes de eliminar) +- [ ] infrastructure legacy (sequencer, dispatcher, etc.) pendiente +- [ ] Macros BIND/SEND/SUBSCRIBE pendiente eliminar +- [ ] Documentación actualizada + +--- + +## FASE 5b: Protocolos de Blockchain (PENDIENTE) + +### Estado Actual +`protocols_coro.hpp` tiene implementados solo protocolos de **capa de red**: +- ✅ `perform_handshake()` - intercambio version/verack +- ✅ `run_ping_pong()` - keepalive +- ✅ `request_addresses()` / `send_addresses()` - intercambio de peers + +### Protocolos Faltantes (Capa de Blockchain) + +**IMPORTANTE**: Sin estos protocolos, el nodo se conecta pero NO sincroniza: + +#### 1. Block Sync Protocol +```cpp +// Mensajes: getblocks, inv, getdata, block +awaitable sync_blocks(peer_session& peer, block_chain& chain); +awaitable handle_block_announcement(peer_session& peer, inv_message const& inv); +awaitable request_blocks(peer_session& peer, std::vector const& hashes); +``` + +#### 2. Header Sync Protocol (Headers-First) +```cpp +// Mensajes: getheaders, headers +awaitable sync_headers(peer_session& peer, block_chain& chain); +awaitable> request_headers( + peer_session& peer, + hash_digest const& from_hash, + hash_digest const& stop_hash); +``` + +#### 3. Transaction Relay Protocol +```cpp +// Mensajes: inv, getdata, tx, mempool +awaitable relay_transaction(peer_session& peer, transaction const& tx); +awaitable handle_tx_announcement(peer_session& peer, inv_message const& inv); +awaitable request_mempool(peer_session& peer); // BIP 35 +``` + +#### 4. Double Spend Proof Protocol (BCH específico) +```cpp +// Mensajes: dsproof-beta +awaitable handle_dsproof(peer_session& peer, dsproof_message const& dsp); +awaitable relay_dsproof(peer_session& peer, dsproof const& proof); +``` + +### Archivos Legacy de Referencia +Usar como referencia para la implementación moderna: +- `src/node/protocols/protocol_block_in.cpp` (eliminado, ver git history) +- `src/node/protocols/protocol_block_out.cpp` (eliminado, ver git history) +- `src/node/protocols/protocol_header_sync.cpp` (eliminado, ver git history) +- `src/node/protocols/protocol_transaction_in.cpp` (eliminado, ver git history) +- `src/node/protocols/protocol_transaction_out.cpp` (eliminado, ver git history) + +### Dependencias +Estos protocolos requieren acceso a: +- `block_chain` para validar y almacenar bloques/headers +- `transaction_pool` (mempool) para transacciones +- Configuración de la red (checkpoints, etc.) + +### Ubicación Sugerida +Crear nuevo archivo: `src/network/include/kth/network/blockchain_protocols_coro.hpp` +O extender `protocols_coro.hpp` con una sección separada + +--- + +## FASE 8: Integration Tests + +### Problema con Tests Unitarios de Networking + +Los tests unitarios tienen limitaciones para probar networking real: +- **Timeouts largos**: Tests de timeout/retry pueden tardar minutos +- **Dependencias externas**: Tests contra nodos reales son flaky +- **Cobertura limitada**: No se pueden testear edge cases de red fácilmente +- **CI/CD lento**: Tests de integración alargan el pipeline + +### Solución: Mock Node + Integration Test Suite + +Crear un **nodo Bitcoin mockeado** en Python que simule un peer de la red, permitiendo: +- Tests locales rápidos y determinísticos +- Simulación de errores de red y timeouts +- Validación de protocolo end-to-end +- Escenarios de edge cases controlados + +### Arquitectura Propuesta + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Integration Test Suite │ +│ (Python/pytest) │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ TCP/IP ┌──────────────────────┐ │ +│ │ │◄─────────────►│ │ │ +│ │ Knuth Node │ │ Mock Bitcoin Node │ │ +│ │ (C++) │ │ (Python) │ │ +│ │ │ │ │ │ +│ └──────────────┘ └──────────────────────┘ │ +│ │ +│ - Binario compilado - Simula protocolo Bitcoin │ +│ - Configuración de test - Respuestas programables │ +│ - Puerto configurable - Inyección de errores │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Mock Node Features + +```python +# tests/integration/mock_node.py + +class MockBitcoinNode: + """Nodo Bitcoin mockeado para integration tests.""" + + def __init__(self, port: int = 18444): + self.port = port + self.connections = [] + self.message_log = [] + + async def start(self): + """Iniciar servidor TCP.""" + pass + + async def stop(self): + """Detener servidor.""" + pass + + # ========================================================================= + # Comportamiento Programable + # ========================================================================= + + def on_version(self, handler: Callable): + """Registrar handler para mensaje version.""" + pass + + def respond_with(self, message_type: str, payload: bytes): + """Programar respuesta automática.""" + pass + + def delay_response(self, message_type: str, seconds: float): + """Simular latencia.""" + pass + + def drop_connection_after(self, message_type: str): + """Simular desconexión.""" + pass + + def send_invalid_magic(self): + """Enviar mensaje con magic incorrecto.""" + pass + + def send_invalid_checksum(self): + """Enviar mensaje con checksum corrupto.""" + pass + + def send_oversized_payload(self, size: int): + """Enviar payload más grande que el límite.""" + pass + + # ========================================================================= + # Assertions + # ========================================================================= + + def assert_received(self, message_type: str, timeout: float = 5.0): + """Verificar que se recibió un mensaje.""" + pass + + def assert_connection_count(self, expected: int): + """Verificar número de conexiones.""" + pass +``` + +### Casos de Test Propuestos + +#### 9.1 Happy Path Tests +```python +# tests/integration/test_handshake.py + +@pytest.mark.integration +async def test_successful_handshake(): + """Knuth completa handshake correctamente.""" + async with MockBitcoinNode() as mock: + mock.respond_with("version", make_version_message()) + mock.respond_with("verack", b"") + + knuth = await start_knuth_node(connect_to=mock.address) + + mock.assert_received("version") + mock.assert_received("verack") + assert knuth.connection_count() == 1 + +@pytest.mark.integration +async def test_ping_pong(): + """Knuth responde a ping con pong.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + mock.send("ping", nonce=12345) + mock.assert_received("pong", nonce=12345) + +@pytest.mark.integration +async def test_addr_exchange(): + """Knuth intercambia direcciones correctamente.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + mock.send("getaddr") + mock.assert_received("addr") +``` + +#### 9.2 Error Handling Tests +```python +# tests/integration/test_errors.py + +@pytest.mark.integration +async def test_invalid_magic_disconnects(): + """Knuth desconecta al recibir magic inválido.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + mock.send_invalid_magic() + + await asyncio.sleep(0.5) + assert mock.connection_count() == 0 + +@pytest.mark.integration +async def test_invalid_checksum_disconnects(): + """Knuth desconecta al recibir checksum inválido.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + mock.send_invalid_checksum() + + await asyncio.sleep(0.5) + assert mock.connection_count() == 0 + +@pytest.mark.integration +async def test_oversized_payload_disconnects(): + """Knuth desconecta al recibir payload muy grande.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + mock.send_oversized_payload(100 * 1024 * 1024) # 100 MB + + await asyncio.sleep(0.5) + assert mock.connection_count() == 0 +``` + +#### 9.3 Timeout Tests +```python +# tests/integration/test_timeouts.py + +@pytest.mark.integration +async def test_handshake_timeout(): + """Knuth desconecta si handshake tarda demasiado.""" + async with MockBitcoinNode() as mock: + # No responder a version + mock.on_version(lambda: None) + + knuth = await start_knuth_node( + connect_to=mock.address, + handshake_timeout=2 + ) + + await asyncio.sleep(3) + assert mock.connection_count() == 0 + +@pytest.mark.integration +async def test_inactivity_timeout(): + """Knuth desconecta después de inactividad.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + # No enviar nada por un rato + await asyncio.sleep(mock.inactivity_timeout + 1) + + assert mock.connection_count() == 0 +``` + +#### 9.4 Reconnection Tests +```python +# tests/integration/test_reconnection.py + +@pytest.mark.integration +async def test_reconnect_after_disconnect(): + """Knuth reconecta después de desconexión.""" + async with MockBitcoinNode() as mock: + await complete_handshake(mock) + + # Forzar desconexión + mock.drop_all_connections() + + # Esperar reconexión + await asyncio.sleep(5) + mock.assert_connection_count(1) + +@pytest.mark.integration +async def test_connect_to_multiple_peers(): + """Knuth puede conectar a múltiples peers.""" + async with MockBitcoinNode(port=18444) as mock1, \ + MockBitcoinNode(port=18445) as mock2: + + knuth = await start_knuth_node( + seeds=[mock1.address, mock2.address] + ) + + await asyncio.sleep(5) + assert knuth.connection_count() >= 2 +``` + +### Estructura de Directorios + +``` +tests/ +├── unit/ # Tests unitarios (C++, Catch2) +│ ├── infrastructure/ +│ ├── domain/ +│ └── network/ +│ +└── integration/ # Integration tests (Python) + ├── conftest.py # Fixtures compartidos + ├── mock_node/ + │ ├── __init__.py + │ ├── server.py # MockBitcoinNode + │ ├── protocol.py # Serialización de mensajes + │ └── messages.py # Builders de mensajes + │ + ├── test_handshake.py # Happy path + ├── test_errors.py # Error handling + ├── test_timeouts.py # Timeouts + ├── test_reconnection.py # Reconnection logic + └── test_protocols.py # Protocol-specific tests +``` + +### Ejecución + +```bash +# Tests unitarios (rápidos, en CI) +cmake --build build --target test + +# Integration tests (más lentos, manual o nightly) +cd tests/integration +pytest -v -m integration + +# Solo happy path (para desarrollo) +pytest -v -m "integration and not slow" + +# Con coverage de protocolos +pytest -v --protocol-coverage +``` + +### Entregables Fase 8 + +- [ ] `MockBitcoinNode` en Python con protocolo básico +- [ ] Fixtures para pytest (`conftest.py`) +- [ ] Tests de handshake (version/verack) +- [ ] Tests de ping/pong +- [ ] Tests de errores (magic, checksum, payload) +- [ ] Tests de timeouts (handshake, inactivity, expiration) +- [ ] Tests de reconexión +- [ ] **Tests de IPv4 e IPv6**: Verificar que el nodo funciona correctamente con ambas familias de direcciones + - [ ] Conexiones entrantes IPv4 + - [ ] Conexiones entrantes IPv6 + - [ ] Conexiones salientes IPv4 + - [ ] Conexiones salientes IPv6 + - [ ] Dual-stack (IPv6 aceptando IPv4-mapped addresses) +- [ ] Script de ejecución para CI (nightly) +- [ ] Documentación de cómo agregar nuevos tests + +--- + +## Timeline Estimado + +| Fase | Descripción | Complejidad | Riesgo | +|------|-------------|-------------|--------| +| 0 | Preparación | Baja | Bajo | +| 1 | Infraestructura Base | Media | Bajo | +| 2 | Proxy/Channel | Alta | Medio | +| 3 | Connector/Acceptor | Media | Bajo | +| 4 | Session Management | Media | Medio | +| 5 | Protocols | Alta | Medio | +| 6 | P2P Node | Alta | Alto | +| 7 | Integración | Media | Alto | +| 8 | Cleanup | Baja | Bajo | +| 9 | Integration Tests | Media | Bajo | + +**Notas**: +- Cada fase puede deployarse independientemente (feature flag) +- La fase 7 es el punto de no retorno +- Mantener backwards compatibility hasta fase 8 + +--- + +## Métricas de Éxito + +1. **Reducción de código**: 50%+ menos líneas en network/infrastructure +2. **Rendimiento**: Sin regresión (idealmente mejora de 5-10%) +3. **Mantenibilidad**: Reducción de callback depth de 4-6 a 0 +4. **Bugs**: Sin nuevos bugs críticos en migración +5. **Tests**: Cobertura mantenida o mejorada + +--- + +## Riesgos y Mitigaciones + +| Riesgo | Probabilidad | Impacto | Mitigación | +|--------|--------------|---------|------------| +| Bugs sutiles en coroutines | Media | Alto | Tests exhaustivos, rollback via feature flag | +| Performance regression | Baja | Medio | Benchmarks en cada fase | +| Breaking changes en Asio experimental | Media | Medio | Pinear versión de Asio | +| Compiladores no soportados | Baja | Alto | Mantener código legacy con #ifdef | + +--- + +## Orden de Implementación Recomendado + +``` +Fase 0 ─────────────────────────────────────────► + │ + ▼ +Fase 1 (thread_pool, helpers) ─────────────────► + │ + ▼ +Fase 2 (peer_session) ─────────────────────────► + │ + ├────► Fase 3 (connector/acceptor) + │ + ▼ +Fase 4 (peer_manager) ─────────────────────────► + │ + ▼ +Fase 5 (protocols) ────────────────────────────► + │ + ▼ +Fase 6 (p2p_node) ─────────────────────────────► + │ + ▼ +Fase 7 (integración) ──────────────────────────► + │ + ▼ +Fase 8 (cleanup) ──────────────────────────────► +``` + +--- + +## Próximos Pasos Inmediatos + +1. **Verificar requisitos**: Comprobar versiones de compiladores y Asio +2. **Crear branch**: `feature/coroutine-migration` +3. **Implementar Fase 0**: Feature flag y smoke test +4. **Comenzar Fase 1**: thread_pool moderno y helpers + +¿Empezamos con la Fase 0? + +--- + +## Fase 7: Integración con full_node (Detallado) + +### Estado Actual + +Actualmente `full_node` hereda de `network::p2p`: + +```cpp +class full_node + : public multi_crypto_setter + , public network::p2p // <-- Herencia problemática +{ + // ... +}; +``` + +Este diseño tiene varios problemas: +1. **Acoplamiento fuerte**: full_node depende de la implementación interna de p2p +2. **Métodos virtuales innecesarios**: No hay polimorfismo real (no hay código que use `p2p*` para manejar un `full_node*`) +3. **Complejidad**: Las sessions de node heredan de sessions de network solo para hacer override de `attach_protocols()` + +### Análisis de Sessions de Node + +Las tres sessions de node (`session_inbound`, `session_outbound`, `session_manual`) son **idénticas** en su método `attach_protocols()`: + +```cpp +void session_XXX::attach_protocols(channel::ptr channel) { + auto const version = channel->negotiated_version(); + + // Protocolos de red (de network::) + if (version >= version::level::bip31) { + attach(channel)->start(); + } else { + attach(channel)->start(); + } + if (version >= domain::message::version::level::bip61) { + attach(channel)->start(); + } + attach(channel)->start(); + + // Protocolos de blockchain (de node::) + attach(channel, chain_)->start(); + attach(channel, chain_)->start(); + attach(channel, chain_)->start(); + attach(channel, chain_)->start(); + attach(channel, chain_)->start(); + attach(channel, chain_)->start(); +} +``` + +### Análisis de Protocolos de Node + +Los protocolos de node heredan de clases base de network: +- `protocol_block_in` : `network::protocol_timer` +- `protocol_block_out` : `network::protocol_events` +- `protocol_block_sync` : `network::protocol_timer` +- `protocol_header_sync` : `network::protocol_timer` +- `protocol_transaction_in` : `network::protocol_events` +- `protocol_transaction_out` : `network::protocol_events` +- `protocol_double_spend_proof_in` : `network::protocol_events` +- `protocol_double_spend_proof_out` : `network::protocol_events` + +Todos usan el patrón callback-based heredado. + +### Nuevo Diseño: Composición en lugar de Herencia + +```cpp +class full_node { +private: + network::p2p_node network_; // Composición en lugar de herencia + blockchain::block_chain chain_; + +public: + full_node(configuration const& config) + : network_(config.network) + , chain_(...) + {} + + // Delegación explícita + ::asio::awaitable start() { + if (!chain_.start()) { + co_return error::operation_failed; + } + co_return co_await network_.start(); + } + + ::asio::awaitable run() { + co_return co_await network_.run(); + } + + void stop() { + network_.stop(); + chain_.stop(); + } + + // Acceso a componentes + network::p2p_node& network() { return network_; } + blockchain::safe_chain& chain() { return chain_; } +}; +``` + +### Protocolos Coroutine Existentes vs Por Crear + +Ya existe `network::protocols_coro` (creado en Fase 5) con protocolos de red genéricos: +- `perform_handshake()` - version/verack +- `run_ping_pong()` - ping/pong keepalive +- `request_addresses()` / `send_addresses()` - getaddr/addr + +El nuevo `node::protocols_coro` extenderá este patrón para protocolos de blockchain. + +### Plan de Implementación + +#### Paso 1: Crear protocol handlers con coroutines en node + +Siguiendo el patrón de `network::protocols_coro`, crear funciones coroutine para protocolos de blockchain: + +```cpp +// src/node/include/kth/node/protocols_coro.hpp + +namespace kth::node { + +/// Run all blockchain protocols for a peer +::asio::awaitable run_blockchain_protocols( + network::peer_session& peer, + blockchain::safe_chain& chain); + +/// Block reception protocol +::asio::awaitable run_block_in_protocol( + network::peer_session& peer, + blockchain::safe_chain& chain); + +/// Block sending protocol +::asio::awaitable run_block_out_protocol( + network::peer_session& peer, + blockchain::safe_chain& chain); + +/// Transaction reception protocol +::asio::awaitable run_transaction_in_protocol( + network::peer_session& peer, + blockchain::safe_chain& chain); + +/// Transaction sending protocol +::asio::awaitable run_transaction_out_protocol( + network::peer_session& peer, + blockchain::safe_chain& chain); + +/// DSP protocols +::asio::awaitable run_dsp_in_protocol( + network::peer_session& peer, + blockchain::safe_chain& chain); + +::asio::awaitable run_dsp_out_protocol( + network::peer_session& peer, + blockchain::safe_chain& chain); + +} // namespace kth::node +``` + +#### Paso 2: Modificar full_node para usar composición + +```cpp +// full_node.hpp +class full_node { +public: + explicit full_node(configuration const& config); + ~full_node(); + + // Lifecycle - ahora async + ::asio::awaitable start(); + ::asio::awaitable run(); + void stop(); + void join(); + + // Properties + network::settings const& network_settings() const; + blockchain::settings const& chain_settings() const; + node::settings const& node_settings() const; + blockchain::safe_chain& chain(); + network::p2p_node& network(); + +private: + // Composición - NO herencia + network::p2p_node network_; + blockchain::block_chain chain_; + + node::settings const& node_settings_; + blockchain::settings const& chain_settings_; +}; +``` + +#### Paso 3: Configurar protocol handlers en p2p_node + +`p2p_node` necesita un mecanismo para que el usuario configure qué protocolos ejecutar con cada peer: + +```cpp +// Opción A: Callback de configuración +using protocol_configurator = std::function<::asio::awaitable(peer_session&)>; + +p2p_node::set_protocol_handler(protocol_configurator handler); + +// Opción B: Template/Strategy +class full_node { + ::asio::awaitable on_peer_connected(network::peer_session::ptr peer) { + // Ejecutar protocolos de network + co_await network::run_ping_pong(*peer, ping_interval); + + // Ejecutar protocolos de blockchain + co_await node::run_blockchain_protocols(*peer, chain_); + } +}; +``` + +#### Paso 4: Eliminar sessions y protocols legacy de node + +Una vez que full_node use composición y los nuevos protocols coro: + +1. Eliminar `src/node/sessions/session_inbound.hpp/.cpp` +2. Eliminar `src/node/sessions/session_outbound.hpp/.cpp` +3. Eliminar `src/node/sessions/session_manual.hpp/.cpp` +4. Eliminar `src/node/sessions/session_block_sync.hpp/.cpp` +5. Eliminar `src/node/sessions/session_header_sync.hpp/.cpp` + +Los protocolos legacy se mantienen temporalmente y se migran gradualmente. + +### Dependencias + +``` +full_node + │ + ├──► network::p2p_node (composición) + │ │ + │ ├──► peer_manager + │ │ └──► peer_session[] + │ │ + │ ├──► hosts (address management) + │ │ + │ └──► protocols_coro (handshake, ping, address) + │ + └──► blockchain::block_chain + │ + └──► node::protocols_coro (block, tx, dsp) +``` + +### Archivos a Modificar/Crear + +| Archivo | Acción | Descripción | +|---------|--------|-------------| +| `src/node/include/kth/node/full_node.hpp` | Modificar | Cambiar herencia a composición | +| `src/node/src/full_node.cpp` | Modificar | Adaptar a nuevo diseño | +| `src/node/include/kth/node/protocols_coro.hpp` | Crear | Nuevos protocols coroutine | +| `src/node/src/protocols_coro.cpp` | Crear | Implementación | +| `src/network/include/kth/network/p2p_node.hpp` | Modificar | Agregar hook para protocols | + +### Archivos Legacy a Eliminar (Fase Cleanup) + +#### Network Layer - Protocolos Legacy (reemplazados por `network::protocols_coro`) + +| Archivo Legacy | Reemplazado Por | +|----------------|-----------------| +| `src/network/include/kth/network/protocols/protocol.hpp` | Base class - ya no necesaria | +| `src/network/src/protocols/protocol.cpp` | | +| `src/network/include/kth/network/protocols/protocol_events.hpp` | Base class - ya no necesaria | +| `src/network/src/protocols/protocol_events.cpp` | | +| `src/network/include/kth/network/protocols/protocol_timer.hpp` | Base class - ya no necesaria | +| `src/network/src/protocols/protocol_timer.cpp` | | +| `src/network/include/kth/network/protocols/protocol_version_31402.hpp` | `perform_handshake()` | +| `src/network/src/protocols/protocol_version_31402.cpp` | | +| `src/network/include/kth/network/protocols/protocol_version_70002.hpp` | `perform_handshake()` | +| `src/network/src/protocols/protocol_version_70002.cpp` | | +| `src/network/include/kth/network/protocols/protocol_ping_31402.hpp` | `run_ping_pong()` | +| `src/network/src/protocols/protocol_ping_31402.cpp` | | +| `src/network/include/kth/network/protocols/protocol_ping_60001.hpp` | `run_ping_pong()` | +| `src/network/src/protocols/protocol_ping_60001.cpp` | | +| `src/network/include/kth/network/protocols/protocol_address_31402.hpp` | `request_addresses()` | +| `src/network/src/protocols/protocol_address_31402.cpp` | | +| `src/network/include/kth/network/protocols/protocol_seed_31402.hpp` | `send_addresses()` | +| `src/network/src/protocols/protocol_seed_31402.cpp` | | +| `src/network/include/kth/network/protocols/protocol_reject_70002.hpp` | Deprecated (BIP 61) | +| `src/network/src/protocols/protocol_reject_70002.cpp` | | + +#### Node Layer - Sessions Legacy (reemplazadas por composición en `full_node`) + +| Archivo Legacy | Notas | +|----------------|-------| +| `src/node/include/kth/node/sessions/session_inbound.hpp` | Solo hacía override de `attach_protocols()` | +| `src/node/src/sessions/session_inbound.cpp` | | +| `src/node/include/kth/node/sessions/session_outbound.hpp` | Solo hacía override de `attach_protocols()` | +| `src/node/src/sessions/session_outbound.cpp` | | +| `src/node/include/kth/node/sessions/session_manual.hpp` | Solo hacía override de `attach_protocols()` | +| `src/node/src/sessions/session_manual.cpp` | | +| `src/node/include/kth/node/sessions/session_block_sync.hpp` | Sincronización de bloques | +| `src/node/src/sessions/session_block_sync.cpp` | | +| `src/node/include/kth/node/sessions/session_header_sync.hpp` | Sincronización de headers | +| `src/node/src/sessions/session_header_sync.cpp` | | + +#### Node Layer - Protocolos Legacy (reemplazados por `node::protocols_coro`) + +| Archivo Legacy | Reemplazado Por | +|----------------|-----------------| +| `src/node/include/kth/node/protocols/protocol_block_in.hpp` | `run_block_in_protocol()` | +| `src/node/src/protocols/protocol_block_in.cpp` | | +| `src/node/include/kth/node/protocols/protocol_block_out.hpp` | `run_block_out_protocol()` | +| `src/node/src/protocols/protocol_block_out.cpp` | | +| `src/node/include/kth/node/protocols/protocol_block_sync.hpp` | `run_block_sync_protocol()` | +| `src/node/src/protocols/protocol_block_sync.cpp` | | +| `src/node/include/kth/node/protocols/protocol_header_sync.hpp` | `run_header_sync_protocol()` | +| `src/node/src/protocols/protocol_header_sync.cpp` | | +| `src/node/include/kth/node/protocols/protocol_transaction_in.hpp` | `run_transaction_in_protocol()` | +| `src/node/src/protocols/protocol_transaction_in.cpp` | | +| `src/node/include/kth/node/protocols/protocol_transaction_out.hpp` | `run_transaction_out_protocol()` | +| `src/node/src/protocols/protocol_transaction_out.cpp` | | +| `src/node/include/kth/node/protocols/protocol_double_spend_proof_in.hpp` | `run_dsp_in_protocol()` | +| `src/node/src/protocols/protocol_double_spend_proof_in.cpp` | | +| `src/node/include/kth/node/protocols/protocol_double_spend_proof_out.hpp` | `run_dsp_out_protocol()` | +| `src/node/src/protocols/protocol_double_spend_proof_out.cpp` | | + +### Riesgos + +1. **Breaking change API**: La API pública de full_node cambia +2. **Migración de protocols**: Los protocols legacy usan muchos callbacks internos +3. **Sincronización**: block_sync y header_sync son complejos + +### Mitigación + +- Mantener compatibilidad parcial con `#ifdef` durante transición +- Migrar protocols uno a uno, probando cada uno +- Dejar sync protocols para el final (o fase separada) + +--- + +## Pendientes + +### Sync & Download + +- [ ] **Descarga paralela de bloques desde múltiples peers** + - Actualmente la descarga de bloques es secuencial (~5-11 bloques/segundo) + - BCHN usa hasta 16 bloques en vuelo por peer, con hasta 8 peers (~128 bloques simultáneos) + - Esto reduciría el tiempo de sync de ~23-46 horas a ~1-2 horas + - Requiere coordinar qué rangos de bloques pide cada peer + - Referencia: BCHN `net_processing.cpp` - `MAX_BLOCKS_IN_TRANSIT_PER_PEER` + +- [ ] **Agregar flag `is_outbound` a `peer_session`** + - Para preferir peers outbound en la selección de sync (como hace BCHN con `fPreferredDownload`) + +### IPv6 + +- [ ] **Investigar problemas con resolución IPv6** + - Actualmente filtrado a IPv4-only en `hosts.cpp` (ver TODO en el código) + - ASIO resolver falla con "Host not found" para muchas direcciones IPv6 + - ¿Es un problema de configuración del resolver o las direcciones son inválidas? + diff --git a/doc/coroutine-migration-status.md b/doc/coroutine-migration-status.md new file mode 100644 index 00000000..cb75d484 --- /dev/null +++ b/doc/coroutine-migration-status.md @@ -0,0 +1,151 @@ +# Coroutine Migration Status + +## Overview + +This document tracks the current state of the coroutine migration for the kth-node P2P networking layer. + +## Completed Work + +### Phase 0-6: Coroutine Infrastructure +- Coroutine configuration and smoke tests +- `peer_session` with connection helpers +- `peer_manager` for unified peer collection management +- Coroutine-based protocol functions (`protocols_coro.hpp/cpp`) +- `p2p_node` unified networking class + +### Phase 7: Headers-First Sync Implementation +- **`sync_session`**: Coordinates headers-first synchronization with peers + - Builds block locators for `getheaders` requests + - Receives headers in batches (up to 2000 per request) + - Delegates validation to `header_organizer` + - Requests blocks via `getdata` for validated headers + +- **`header_organizer`**: Manages header caching and validation during IBD + - In-memory cache with configurable memory limits (default 256 MB) + - Memory-aware caching with auto-flush when threshold reached + - Thread-safe (mutex-protected public methods) + - Batch persistence to database via `chain_.organize_headers_batch()` + +- **`validate_header`**: Header validation logic + - Context-free validation (PoW check) + - Chain-context validation (previous hash, checkpoints) + - Checkpoint conflict detection with detailed logging + +- **`broadcaster`**: Template-based async channel broadcaster + - Manages multiple subscribers with thread-safe operations + - Uses `asio::experimental::concurrent_channel` + +- **`system_memory`**: Cross-platform memory estimation utilities + - `get_available_system_memory()` for cache sizing decisions + +### Infrastructure Changes +- Deprecated legacy callback-based utilities (`dispatcher`, `sequencer`, `subscriber`, etc.) +- Moved legacy network code to `deprecated/` folders +- Added `block_chain::organize_headers_batch()` for batch header storage + +## Current Issues / Known Problems + +### Headers-First Sync +1. **Checkpoint validation failing**: Headers sync stops at checkpoint heights with hash mismatch + - Need to investigate if checkpoints are correct for the network being tested + - Added detailed logging to `validate_header::is_checkpoint_conflict()` + +2. **Cache flush on destruction**: Warning appears when organizer is destroyed with unflushed headers + - This is expected behavior when sync fails, but should flush on graceful shutdown + +3. **Single-peer sync**: Currently syncs from one peer only + - Future: parallel downloads from multiple peers + +### Block Sync +- Block download phase (`sync_blocks`) is implemented but untested +- `block_chain::organize()` integration needs validation + +## TODO / Next Steps + +### High Priority +1. **Fix checkpoint validation** + - Verify checkpoint hashes match the target network (mainnet vs testnet vs chipnet) + - Add network-specific checkpoint loading + +2. **Test block download phase** + - Validate `getdata` / `block` message exchange + - Test `block_chain::organize()` integration + +3. **Graceful shutdown** + - Ensure `header_organizer::flush()` is called on clean shutdown + - Add proper cancellation to `sync_session::run()` + +### Medium Priority +4. **Parallel block downloads** + - Request blocks from multiple peers simultaneously + - Implement download scheduling/prioritization + +5. **Sync progress reporting** + - Add callbacks/channels for sync progress updates + - Integrate with TUI dashboard + +6. **Error recovery** + - Handle peer disconnection during sync + - Automatic peer rotation on failure + +### Low Priority +7. **Performance optimization** + - Profile header validation performance + - Optimize memory allocation patterns + +8. **Delete deprecated code** + - Remove `deprecated/` folders after full validation + - Clean up unused callback-based infrastructure + +## Architecture Diagram + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ full_node │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ p2p_node │ │ block_chain │ │ sync_session │ │ +│ │ │ │ │ │ ┌─────────────────────┐│ │ +│ │ peer_manager│ │ organize() │◄─┼──│ header_organizer ││ │ +│ │ │ │ organize_ │ │ │ ┌────────────────┐ ││ │ +│ │peer_sessions│ │ headers_ │ │ │ │validate_header │ ││ │ +│ │ │ │ batch() │ │ │ └────────────────┘ ││ │ +│ └─────────────┘ └─────────────┘ │ └─────────────────────┘│ │ +│ │ │ │ │ │ +│ └──────────────────────────┼───────────┘ │ │ +│ peer_session:: │ │ │ +│ send/receive │ │ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## File Inventory + +### New Files (this PR) +- `src/blockchain/include/kth/blockchain/pools/header_organizer.hpp` +- `src/blockchain/src/pools/header_organizer.cpp` +- `src/blockchain/include/kth/blockchain/validate/validate_header.hpp` +- `src/blockchain/src/validate/validate_header.cpp` +- `src/node/include/kth/node/sync_session.hpp` +- `src/node/src/sync_session.cpp` +- `src/infrastructure/include/kth/infrastructure/utility/broadcaster.hpp` +- `src/infrastructure/include/kth/infrastructure/utility/system_memory.hpp` +- `src/infrastructure/src/utility/system_memory.cpp` + +### Modified Files (key changes) +- `src/node/src/full_node.cpp` - Integrated `sync_from_best_peer()` +- `src/blockchain/src/interface/block_chain.cpp` - Added `organize_headers_batch()` +- `src/blockchain/include/kth/blockchain.hpp` - Export new headers + +## Testing Notes + +### Manual Testing Performed +- Compilation: OK +- Node startup: OK +- Peer connections: OK (connects to mainnet peers) +- Headers reception: OK (receives 2000 headers per batch) +- Headers validation: Partial (fails at checkpoints, needs investigation) +- Block download: Not tested + +### Automated Tests Needed +- Unit tests for `validate_header` +- Unit tests for `header_organizer` +- Integration tests for `sync_session` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e74876f..9023f1d1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ if (BUILD_NODE_EXE AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") add_subdirectory(node-exe) endif() -if (BUILD_C_API) - add_subdirectory(c-api) -endif() \ No newline at end of file +# TODO(fernando): DESCOMENTAR ESTO CUANDO TERMINEMOS EL CLEANUP DE COROUTINES +# if (BUILD_C_API) +# add_subdirectory(c-api) +# endif() \ No newline at end of file diff --git a/src/blockchain/CMakeLists.txt b/src/blockchain/CMakeLists.txt index 4c05beee..2e6a8522 100644 --- a/src/blockchain/CMakeLists.txt +++ b/src/blockchain/CMakeLists.txt @@ -133,6 +133,7 @@ set(kth_sources_just_legacy src/pools/block_organizer.cpp src/pools/block_pool.cpp src/pools/branch.cpp + src/pools/header_organizer.cpp src/pools/transaction_entry.cpp src/pools/transaction_organizer.cpp src/pools/transaction_pool.cpp @@ -142,6 +143,7 @@ set(kth_sources_just_legacy src/populate/populate_chain_state.cpp src/populate/populate_transaction.cpp src/validate/validate_block.cpp + src/validate/validate_header.cpp src/validate/validate_input.cpp src/validate/validate_transaction.cpp src/settings.cpp @@ -161,17 +163,16 @@ set(kth_sources set(kth_headers include/kth/blockchain.hpp include/kth/blockchain/interface - include/kth/blockchain/interface/fast_chain.hpp include/kth/blockchain/interface/block_chain.hpp - include/kth/blockchain/interface/safe_chain.hpp include/kth/blockchain/define.hpp include/kth/blockchain/populate/populate_transaction.hpp include/kth/blockchain/populate/populate_chain_state.hpp include/kth/blockchain/populate/populate_block.hpp include/kth/blockchain/populate/populate_base.hpp + include/kth/blockchain/validate/validate_block.hpp + include/kth/blockchain/validate/validate_header.hpp include/kth/blockchain/validate/validate_input.hpp include/kth/blockchain/validate/validate_transaction.hpp - include/kth/blockchain/validate/validate_block.hpp include/kth/blockchain/pools/block_entry.hpp include/kth/blockchain/pools/transaction_pool.hpp include/kth/blockchain/pools/transaction_entry.hpp @@ -179,6 +180,7 @@ set(kth_headers include/kth/blockchain/pools/block_organizer.hpp include/kth/blockchain/pools/branch.hpp include/kth/blockchain/pools/block_pool.hpp + include/kth/blockchain/pools/header_organizer.hpp include/kth/blockchain/pools/transaction_organizer.hpp include/kth/blockchain/mining/mempool_v1_old.hpp include/kth/blockchain/mining/prioritizer.hpp diff --git a/src/blockchain/conanfile.py b/src/blockchain/conanfile.py deleted file mode 100644 index 5b5e3e2d..00000000 --- a/src/blockchain/conanfile.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" - -class KnuthBlockchainConan(KnuthConanFileV2): - name = "blockchain" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/blockchain/blob/conan-build/conanfile.py" - description = "Knuth Blockchain Library" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = { - "shared": [True, False], - "fPIC": [True, False], - "consensus": [True, False], - "tests": [True, False], - "tools": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - "verbose": [True, False], - "mempool": [True, False], - "db": ['dynamic'], - "db_readonly": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "consensus": True, - "tests": True, - "tools": False, - "currency": "BCH", - "march_strategy": "download_if_possible", - "verbose": False, - "mempool": False, - "db": "dynamic", - "db_readonly": False, - "cmake_export_compile_commands": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "knuthbuildinfo.cmake", "include/*", "test/*", "tools/*" - - def _is_legacy_db(self): - return self.options.db == "legacy" or self.options.db == "legacy_full" - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def requirements(self): - self.requires("database/0.51.0", transitive_headers=True, transitive_libs=True) - if self.options.consensus: - self.requires("consensus/0.38.0", transitive_headers=True, transitive_libs=True) - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - self.options["*"].db_readonly = self.options.db_readonly - self.output.info("Compiling with read-only DB: %s" % (self.options.db_readonly,)) - - # self.options["*"].mining = self.options.mining - # self.options["*"].mempool = self.options.mempool - # self.output.info("Compiling with mining optimizations: %s" % (self.options.mining,)) - self.output.info("Compiling with mempool: %s" % (self.options.mempool,)) - - - def package_id(self): - KnuthConanFileV2.package_id(self) - self.info.options.tools = "ANY" - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - tc.variables["WITH_CONSENSUS"] = option_on_off(self.options.consensus) - # tc.variables["WITH_MINING"] = option_on_off(self.options.mining) - tc.variables["WITH_MEMPOOL"] = option_on_off(self.options.mempool) - tc.variables["DB_READONLY_MODE"] = option_on_off(self.options.db_readonly) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - if not self.options.cmake_export_compile_commands: - cmake.build() - if self.options.tests: - cmake.test() - - def package(self): - cmake = CMake(self) - cmake.install() - # rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - # rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) - # rmdir(self, os.path.join(self.package_folder, "res")) - # rmdir(self, os.path.join(self.package_folder, "share")) - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["blockchain"] diff --git a/src/blockchain/include/kth/blockchain.hpp b/src/blockchain/include/kth/blockchain.hpp index a20893e6..f41829a8 100644 --- a/src/blockchain/include/kth/blockchain.hpp +++ b/src/blockchain/include/kth/blockchain.hpp @@ -21,12 +21,11 @@ #include #include #include -#include -#include #include #include #include #include +#include #include #include #include @@ -35,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp index 92c0e424..c94932c1 100644 --- a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp +++ b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp @@ -10,387 +10,346 @@ #include #include #include +#include #include -// #include #include #include +#include + #include -#include -#include #include +#include +#include #include #include #include +#include +#include + #if defined(KTH_WITH_MEMPOOL) #include #endif namespace kth::blockchain { -/// The fast_chain interface portion of this class is not thread safe. -struct KB_API block_chain : safe_chain, fast_chain, noncopyable { -public: - /// Relay transactions is network setting that is passed through to block - /// population as an optimization. This can be removed once there is an - /// in-memory cache of tx pool metadata, as the costly query will go away. - block_chain(threadpool& pool - , blockchain::settings const& chain_settings - , database::settings const& database_settings - , domain::config::network network - , bool relay_transactions = true); - - /// The database is closed on destruct, threads must be joined. +using kth::awaitable_expected; + +/// Unified blockchain interface. +/// Thread safety: get_* methods are NOT thread safe, fetch_* methods are thread safe. +struct KB_API block_chain { + using executor_type = ::asio::any_io_executor; + + //TODO: unordered_flat_map or concurrent_flat_map (do we need concurrency here?) + using mempool_mini_hash_map = std::unordered_map; + + // ========================================================================= + // CONSTRUCTION + // ========================================================================= + + block_chain(threadpool& pool, + blockchain::settings const& chain_settings, + database::settings const& database_settings, + domain::config::network network, + bool relay_transactions = true); + ~block_chain(); - // ======================================================================== - // FAST CHAIN - // ======================================================================== + // Non-copyable, non-movable + block_chain(block_chain const&) = delete; + block_chain& operator=(block_chain const&) = delete; + block_chain(block_chain&&) = delete; + block_chain& operator=(block_chain&&) = delete; - // Readers. - // ------------------------------------------------------------------------ - // Thread safe, unprotected by sequential lock. + // ========================================================================= + // LIFECYCLE + // ========================================================================= - /// Get the output that is referenced by the outpoint. - bool get_output(domain::chain::output& out_output, size_t& out_height, uint32_t& out_median_time_past, bool& out_coinbase, const domain::chain::output_point& outpoint, size_t branch_height, bool require_confirmed) const override; + [[nodiscard]] bool start(); + [[nodiscard]] bool stop(); + [[nodiscard]] bool close(); + [[nodiscard]] bool stopped() const; - /// Get position data for a transaction. - bool get_transaction_position(size_t& out_height, size_t& out_position, hash_digest const& hash, bool require_confirmed) const override; + // ========================================================================= + // ORGANIZERS (Core blockchain operations) + // ========================================================================= - /// Get the output that is referenced by the outpoint in the UTXO Set. - bool get_utxo(domain::chain::output& out_output, size_t& out_height, uint32_t& out_median_time_past, bool& out_coinbase, domain::chain::output_point const& outpoint, size_t branch_height) const override; + [[nodiscard]] + ::asio::awaitable organize(block_const_ptr block); - std::pair get_utxo_pool_from(uint32_t from, uint32_t to) const override; + [[nodiscard]] + ::asio::awaitable organize(transaction_const_ptr tx); - /// Get a determination of whether the block hash exists in the store. - bool get_block_exists(hash_digest const& block_hash) const override; + [[nodiscard]] + ::asio::awaitable organize(double_spend_proof_const_ptr ds_proof); - /// Get a determination of whether the block hash exists in the store. - bool get_block_exists_safe(hash_digest const& block_hash) const override; + // Headers-first sync: organize a header without full block data + [[nodiscard]] + ::asio::awaitable organize_header(header_const_ptr header); - /// Get the work of the branch starting at the given height. - bool get_branch_work(uint256_t& out_work, uint256_t const& maximum, size_t height) const override; + // Headers-first sync: organize multiple headers in a single batch + [[nodiscard]] + code organize_headers_batch(domain::chain::header::list const& headers, size_t start_height); - /// Get the header of the block at the given height. - bool get_header(domain::chain::header& out_header, size_t height) const override; +#if ! defined(KTH_DB_READONLY) + [[nodiscard]] + awaitable_expected reorganize( + infrastructure::config::checkpoint const& fork_point, + block_const_ptr_list_const_ptr incoming_blocks); - /// Get the header of the block with the given height, also the ABLA state. - std::optional get_header_and_abla_state(size_t height) const override; + [[nodiscard]] + ::asio::awaitable push(transaction_const_ptr tx); - /// Get a sequence of block headers [from, to]. - domain::chain::header::list get_headers(size_t from, size_t to) const override; + [[nodiscard]] code push_sync(transaction_const_ptr tx); + [[nodiscard]] bool insert(block_const_ptr block, size_t height); + void prune_reorg_async(); +#endif - /// Get the height of the block with the given hash. - bool get_height(size_t& out_height, hash_digest const& block_hash) const override; + // ========================================================================= + // CHAIN STATE + // ========================================================================= - /// Get the bits of the block with the given height. - bool get_bits(uint32_t& out_bits, size_t height) const override; + domain::chain::chain_state::ptr chain_state() const; + domain::chain::chain_state::ptr chain_state(branch::const_ptr branch) const; - /// Get the timestamp of the block with the given height. - bool get_timestamp(uint32_t& out_timestamp, size_t height) const override; + // ========================================================================= + // SUBSCRIPTIONS + // ========================================================================= - /// Get the version of the block with the given height. - bool get_version(uint32_t& out_version, size_t height) const override; + using block_channel_ptr = block_organizer::block_broadcaster::channel_ptr; + using transaction_channel_ptr = transaction_organizer::transaction_broadcaster::channel_ptr; + using ds_proof_channel_ptr = transaction_organizer::ds_proof_broadcaster::channel_ptr; - /// Get height of latest block. - bool get_last_height(size_t& out_height) const override; + [[nodiscard]] + block_channel_ptr subscribe_blockchain(); + [[nodiscard]] + transaction_channel_ptr subscribe_transaction(); + [[nodiscard]] + ds_proof_channel_ptr subscribe_ds_proof(); -#if ! defined(KTH_DB_READONLY) - void prune_reorg_async() override; + void unsubscribe_blockchain(block_channel_ptr const& channel); + void unsubscribe_transaction(transaction_channel_ptr const& channel); + void unsubscribe_ds_proof(ds_proof_channel_ptr const& channel); + + // ========================================================================= + // VALIDATION + // ========================================================================= + + [[nodiscard]] + ::asio::awaitable transaction_validate(transaction_const_ptr tx) const; + + // ========================================================================= + // PROPERTIES + // ========================================================================= + + bool is_stale() const; + settings const& chain_settings() const; + executor_type executor() const; + +#if defined(KTH_WITH_MEMPOOL) + std::pair, uint64_t> get_block_template() const; #endif - //void set_database_flags() override; + // ========================================================================= + // DATABASE READERS (Low-level, NOT thread safe) + // ========================================================================= - /// Get the hash of the block if it exists. - bool get_block_hash(hash_digest& out_hash, size_t height) const override; + [[nodiscard]] std::expected, database::result_code> get_last_heights() const; + [[nodiscard]] std::expected get_header(size_t height) const; + [[nodiscard]] std::expected get_header_and_abla_state(size_t height) const; + [[nodiscard]] std::expected get_headers(size_t from, size_t to) const; + [[nodiscard]] std::expected get_height(hash_digest const& block_hash) const; + [[nodiscard]] std::expected get_bits(size_t height) const; + [[nodiscard]] std::expected get_timestamp(size_t height) const; + [[nodiscard]] std::expected get_version(size_t height) const; + [[nodiscard]] std::expected get_block_hash(size_t height) const; + [[nodiscard]] std::expected get_branch_work(uint256_t const& maximum, size_t height) const; + struct output_info { + domain::chain::output output; + size_t height; + uint32_t median_time_past; + bool coinbase; + }; - /////// Get the transaction of the given hash and its block height. - ////transaction_ptr get_transaction(size_t& out_block_height, - //// hash_digest const& hash, bool require_confirmed) const; + [[nodiscard]] std::expected get_output( + domain::chain::output_point const& outpoint, + size_t branch_height, bool require_confirmed) const; - // Writers. - // ------------------------------------------------------------------------ - // Thread safe, insert does not set sequential lock. + [[nodiscard]] std::expected get_utxo( + domain::chain::output_point const& outpoint, size_t branch_height) const; -#if ! defined(KTH_DB_READONLY) + [[nodiscard]] std::expected get_utxo_pool_from(uint32_t from, uint32_t to) const; - /// Insert a block to the blockchain, height is checked for existence. - /// Reads and reorgs are undefined when chain is gapped. - bool insert(block_const_ptr block, size_t height) override; - // bool insert(block_const_ptr block, size_t height, int) override; + [[nodiscard]] std::expected, database::result_code> get_transaction_position( + hash_digest const& hash, bool require_confirmed) const; - /// Push an unconfirmed transaction to the tx table and index outputs. - void push(transaction_const_ptr tx, dispatcher& dispatch, result_handler handler) override; + [[nodiscard]] bool block_exists(hash_digest const& block_hash) const; - /// Swap incoming and outgoing blocks, height is validated. - void reorganize(const infrastructure::config::checkpoint& fork_point, - block_const_ptr_list_const_ptr incoming_blocks, - block_const_ptr_list_ptr outgoing_blocks, dispatcher& dispatch, - result_handler handler) override; + // ========================================================================= + // FETCH OPERATIONS (Thread safe, coroutine-based) + // ========================================================================= -#endif // ! defined(KTH_DB_READONLY) + // Block fetching + [[nodiscard]] awaitable_expected> + fetch_block(size_t height) const; - // Properties - // ------------------------------------------------------------------------ + [[nodiscard]] awaitable_expected> + fetch_block(hash_digest const& hash) const; - /// Get forks chain state relative to chain top. - domain::chain::chain_state::ptr chain_state() const override; + [[nodiscard]] awaitable_expected> + fetch_block_header(size_t height) const; - /// Get full chain state relative to the branch top. - domain::chain::chain_state::ptr chain_state(branch::const_ptr branch) const override; + [[nodiscard]] awaitable_expected> + fetch_block_header(hash_digest const& hash) const; - // ======================================================================== - // SAFE CHAIN - // ======================================================================== - // Thread safe. + [[nodiscard]] awaitable_expected + fetch_block_height(hash_digest const& hash) const; - // Startup and shutdown. - // ------------------------------------------------------------------------ - // Thread safe except start. + [[nodiscard]] awaitable_expected> + fetch_block_hash_timestamp(size_t height) const; - /// Start the block pool and the transaction pool. - bool start() override; + [[nodiscard]] awaitable_expected, uint64_t>> + fetch_block_header_txs_size(hash_digest const& hash) const; - /// Signal pool work stop, speeds shutdown with multiple threads. - bool stop() override; + [[nodiscard]] awaitable_expected + fetch_last_height() const; - /// Unmaps all memory and frees the database file handles. - /// Threads must be joined before close is called (or by destruct). - bool close() override; + // Merkle/Compact blocks + [[nodiscard]] awaitable_expected> + fetch_merkle_block(size_t height) const; - // Node Queries. - // ------------------------------------------------------------------------ + [[nodiscard]] awaitable_expected> + fetch_merkle_block(hash_digest const& hash) const; - /// fetch a block by height. - void fetch_block(size_t height, block_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected> + fetch_compact_block(size_t height) const; - /// fetch a block by hash. - void fetch_block(hash_digest const& hash, block_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected> + fetch_compact_block(hash_digest const& hash) const; - /// fetch the set of block hashes indicated by the block locator. - void fetch_locator_block_hashes(get_blocks_const_ptr locator, hash_digest const& threshold, size_t limit, inventory_fetch_handler handler) const override; + // Transaction fetching + [[nodiscard]] awaitable_expected> + fetch_transaction(hash_digest const& hash, bool require_confirmed) const; - void fetch_block_header_txs_size(hash_digest const& hash, block_header_txs_size_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected> + fetch_transaction_position(hash_digest const& hash, bool require_confirmed) const; - /// fetch hashes of transactions for a block, by block height. - void fetch_merkle_block(size_t height, merkle_block_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected + fetch_unconfirmed_transaction(hash_digest const& hash) const; - /// fetch hashes of transactions for a block, by block hash. - void fetch_merkle_block(hash_digest const& hash, merkle_block_fetch_handler handler) const override; + // Locator operations + [[nodiscard]] awaitable_expected + fetch_locator_block_hashes(get_blocks_const_ptr locator, hash_digest const& threshold, size_t limit) const; - /// fetch compact block by block height. - void fetch_compact_block(size_t height, compact_block_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected + fetch_locator_block_headers(get_headers_const_ptr locator, hash_digest const& threshold, size_t limit) const; - /// fetch compact block by block hash. - void fetch_compact_block(hash_digest const& hash, compact_block_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected + fetch_block_locator(domain::chain::block::indexes const& heights) const; - /// fetch DSProof by hash. - void fetch_ds_proof(hash_digest const& hash, ds_proof_fetch_handler handler) const override; + // Server queries + [[nodiscard]] awaitable_expected + fetch_spend(domain::chain::output_point const& outpoint) const; - // void for_each_transaction(size_t from, size_t to, for_each_tx_handler const& handler) const override; + [[nodiscard]] awaitable_expected + fetch_history(short_hash const& address_hash, size_t limit, size_t from_height) const; - // void for_each_transaction_non_coinbase(size_t from, size_t to, for_each_tx_handler const& handler) const override; + [[nodiscard]] awaitable_expected> + fetch_confirmed_transactions(short_hash const& address_hash, size_t limit, size_t from_height) const; - /// fetch transaction by hash. - void fetch_transaction(hash_digest const& hash, bool require_confirmed, transaction_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected + fetch_ds_proof(hash_digest const& hash) const; - /// fetch position and height within block of transaction by hash. - void fetch_transaction_position(hash_digest const& hash, bool require_confirmed, transaction_index_fetch_handler handler) const override; + // ========================================================================= + // MEMPOOL / TRANSACTION POOL + // ========================================================================= - /// fetch the set of block headers indicated by the block locator. - void fetch_locator_block_headers(get_headers_const_ptr locator, hash_digest const& threshold, size_t limit, locator_block_headers_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected> + fetch_template() const; - /// fetch a block locator relative to the current top and threshold. - void fetch_block_locator(domain::chain::block::indexes const& heights, block_locator_fetch_handler handler) const override; + [[nodiscard]] awaitable_expected + fetch_mempool(size_t count_limit, uint64_t minimum_fee) const; - /// fetch height of latest block. - void fetch_last_height(last_height_fetch_handler handler) const override; + std::vector get_mempool_transactions(std::vector const& payment_addresses, bool use_testnet_rules) const; + std::vector get_mempool_transactions(std::string const& payment_address, bool use_testnet_rules) const; + std::vector get_mempool_transactions_from_wallets(std::vector const& payment_addresses, bool use_testnet_rules) const; - /// fetch block header by height. - void fetch_block_header(size_t height, block_header_fetch_handler handler) const override; + mempool_mini_hash_map get_mempool_mini_hash_map(domain::message::compact_block const& block) const; + void fill_tx_list_from_mempool(domain::message::compact_block const& block, size_t& mempool_count, std::vector& txn_available, std::unordered_map const& shorttxids) const; - /// fetch block header by hash. - void fetch_block_header(hash_digest const& hash, block_header_fetch_handler handler) const override; + // ========================================================================= + // FILTERS + // ========================================================================= - /// fetch height of block by hash. - void fetch_block_height(hash_digest const& hash, block_height_fetch_handler handler) const override; + [[nodiscard]] ::asio::awaitable + filter_blocks(get_data_ptr message) const; - void fetch_block_hash_timestamp(size_t height, block_hash_time_fetch_handler handler) const override; + [[nodiscard]] ::asio::awaitable + filter_transactions(get_data_ptr message) const; - // Knuth non-virtual functions. - //------------------------------------------------------------------------- + // ========================================================================= + // ITERATION HELPERS + // ========================================================================= - template - void for_each_tx_hash(I f, I l, size_t height, for_each_tx_handler handler) const { + template + void for_each_tx_hash(I f, I l, size_t height, Handler handler) const { while (f != l) { auto const& hash = *f; auto const tx_result = database_.internal_db().get_transaction(hash, max_size_t); - if ( ! tx_result.is_valid()) { + if ( ! tx_result) { handler(error::transaction_lookup_failed, 0, domain::chain::transaction{}); return; } - KTH_ASSERT(tx_result.height() == height); - handler(error::success, height, tx_result.transaction()); + KTH_ASSERT(tx_result->height() == height); + handler(error::success, height, tx_result->transaction()); ++f; } } - template - void for_each_tx_valid(I f, I l, size_t height, for_each_tx_handler handler) const { + template + void for_each_tx_valid(I f, I l, size_t height, Handler handler) const { while (f != l) { auto const& tx = *f; - if ( ! tx.is_valid()) { handler(error::transaction_lookup_failed, 0, domain::chain::transaction{}); return; } - //KTH_ASSERT(tx.height() == height); handler(error::success, height, tx); ++f; } } - // Server Queries. - //------------------------------------------------------------------------- - - /// fetch the inpoint (spender) of an outpoint. - void fetch_spend(const domain::chain::output_point& outpoint, spend_fetch_handler handler) const override; - /// fetch outputs, values and spends for an address_hash. - void fetch_history(short_hash const& address_hash, size_t limit, size_t from_height, history_fetch_handler handler) const override; - - /// Fetch all the txns used by the wallet - void fetch_confirmed_transactions(short_hash const& address_hash, size_t limit, size_t from_height, confirmed_transactions_fetch_handler handler) const override; - -// /// fetch stealth results. -// void fetch_stealth(binary const& filter, size_t from_height, stealth_fetch_handler handler) const override; - - // Transaction Pool. - //------------------------------------------------------------------------- - - /// Fetch a merkle block for the maximal fee block template. - void fetch_template(merkle_block_fetch_handler handler) const override; - - /// Fetch an inventory vector for a rational "mempool" message response. - void fetch_mempool(size_t count_limit, uint64_t minimum_fee, inventory_fetch_handler handler) const override; - - - std::vector get_mempool_transactions(std::vector const& payment_addresses, bool use_testnet_rules) const override; - std::vector get_mempool_transactions(std::string const& payment_address, bool use_testnet_rules) const override; - std::vector get_mempool_transactions_from_wallets(std::vector const& payment_addresses, bool use_testnet_rules) const override; - - /// fetch unconfirmed transaction by hash. - void fetch_unconfirmed_transaction(hash_digest const& hash, transaction_unconfirmed_fetch_handler handler) const override; - - mempool_mini_hash_map get_mempool_mini_hash_map(domain::message::compact_block const& block) const override; - void fill_tx_list_from_mempool(domain::message::compact_block const& block, size_t& mempool_count, std::vector& txn_available, std::unordered_map const& shorttxids) const override; - - // Filters. - //------------------------------------------------------------------------- - - /// Filter out block by hash that exist in the block pool or store. - void filter_blocks(get_data_ptr message, result_handler handler) const override; - - /// Filter out confirmed and unconfirmed transactions by hash. - void filter_transactions(get_data_ptr message, result_handler handler) const override; - - // Subscribers. - //------------------------------------------------------------------------- - - /// Subscribe to blockchain reorganizations, get branch/height. - void subscribe_blockchain(reorganize_handler&& handler) override; - - /// Subscribe to memory pool additions, get transaction. - void subscribe_transaction(transaction_handler&& handler) override; - - /// Subscribe to DSProof pool additions, get DSProof object. - void subscribe_ds_proof(ds_proof_handler&& handler) override; - - /// Send null data success notification to all subscribers. - void unsubscribe() override; - - // Transaction Validation. - //----------------------------------------------------------------------------- - - void transaction_validate(transaction_const_ptr tx, result_handler handler) const override; - - // Organizers. - //------------------------------------------------------------------------- - - /// Organize a block into the block pool if valid and sufficient. - void organize(block_const_ptr block, result_handler handler) override; - - /// Store a transaction to the pool if valid. - void organize(transaction_const_ptr tx, result_handler handler) override; - - /// Store a DSProof to the pool if valid. - void organize(double_spend_proof_const_ptr ds_proof, result_handler handler) override; - - // Properties. - //------------------------------------------------------------------------- - - /// True if the blockchain is stale based on configured age limit. - bool is_stale() const override; - - /// True if the blockchain is stale based on configured age limit. - bool is_stale_fast() const override; - - /// Get a reference to the blockchain configuration settings. - settings const& chain_settings() const; - -#if defined(KTH_WITH_MEMPOOL) - std::pair, uint64_t> get_block_template() const; -#endif - -protected: - - /// Determine if work should terminate early with service stopped code. - bool stopped() const; - private: using handle = database::data_base::handle; - // Locking helpers. - // ------------------------------------------------------------------------ - template void read_serial(R const& reader) const; template bool finish_read(handle sequence, Handler handler, Args... args) const; - // Utilities. - //------------------------------------------------------------------------- - code set_chain_state(domain::chain::chain_state::ptr previous); - void handle_transaction(code const& ec, transaction_const_ptr tx, result_handler handler) const; - void handle_block(code const& ec, block_const_ptr block, result_handler handler) const; - void handle_reorganize(code const& ec, block_const_ptr top, result_handler handler); - // These are thread safe. + // Thread safe members std::atomic stopped_; settings const& settings_; time_t const notify_limit_seconds_; kth::atomic last_block_; - //TODO(kth): dissabled this tx cache because we don't want special treatment for the last txn, it affects the explorer rpc methods - //kth::atomic last_transaction_; - populate_chain_state const chain_state_populator_; database::data_base database_; - // This is protected by mutex. + // Protected by mutex domain::chain::chain_state::ptr pool_state_; mutable shared_mutex pool_state_mutex_; - // These are thread safe. + // Thread safe mutable prioritized_mutex validation_mutex_; mutable threadpool priority_pool_; - mutable dispatcher dispatch_; - #if defined(KTH_WITH_MEMPOOL) mining::mempool mempool_; diff --git a/src/blockchain/include/kth/blockchain/interface/fast_chain.hpp b/src/blockchain/include/kth/blockchain/interface/fast_chain.hpp deleted file mode 100644 index 31cd30b4..00000000 --- a/src/blockchain/include/kth/blockchain/interface/fast_chain.hpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_BLOCKCHAIN_FAST_CHAIN_HPP -#define KTH_BLOCKCHAIN_FAST_CHAIN_HPP - -#include -#include -#include -#include - -namespace kth::blockchain { - -/// A low level interface for encapsulation of the blockchain database. -/// Caller must ensure the database is not otherwise in use during these calls. -/// Implementations are NOT expected to be thread safe with the exception -/// that the import method may itself be called concurrently. -struct KB_API fast_chain { - // This avoids conflict with the result_handler in safe_chain. - using complete_handler = handle0; - - // Readers. - // ------------------------------------------------------------------------ - - /// Get position data for a transaction. - virtual bool get_transaction_position(size_t& out_height, size_t& out_position, hash_digest const& hash, bool require_confirmed) const = 0; - - /// Get the output that is referenced by the outpoint. - virtual bool get_output(domain::chain::output& out_output, size_t& out_height, uint32_t& out_median_time_past, bool& out_coinbase, const domain::chain::output_point& outpoint, size_t branch_height, bool require_confirmed) const = 0; - - /// Get a determination of whether the block hash exists in the store. - virtual bool get_block_exists(hash_digest const& block_hash) const = 0; - - /// Get the hash of the block if it exists. - virtual bool get_block_hash(hash_digest& out_hash, size_t height) const = 0; - - /// Get the work of the branch starting at the given height. - virtual bool get_branch_work(uint256_t& out_work, uint256_t const& maximum, size_t from_height) const = 0; - - /// Get the header of the block at the given height. - virtual bool get_header(domain::chain::header& out_header, size_t height) const = 0; - - /// Get the header of the block with the given height, also the ABLA state. - virtual std::optional get_header_and_abla_state(size_t height) const = 0; - - /// Get a sequence of block headers [from, to]. - virtual domain::chain::header::list get_headers(size_t from, size_t to) const = 0; - - /// Get the height of the block with the given hash. - virtual bool get_height(size_t& out_height, hash_digest const& block_hash) const = 0; - - /// Get the bits of the block with the given height. - virtual bool get_bits(uint32_t& out_bits, size_t height) const = 0; - - /// Get the timestamp of the block with the given height. - virtual bool get_timestamp(uint32_t& out_timestamp, size_t height) const = 0; - - /// Get the version of the block with the given height. - virtual bool get_version(uint32_t& out_version, size_t height) const = 0; - - /// Get height of latest block. - virtual bool get_last_height(size_t& out_height) const = 0; - - /// Get the output that is referenced by the outpoint in the UTXO Set. - virtual bool get_utxo(domain::chain::output& out_output, size_t& out_height, uint32_t& out_median_time_past, bool& out_coinbase, domain::chain::output_point const& outpoint, size_t branch_height) const = 0; - - /// Get a UTXO subset from the reorganization pool, [from, to] the specified heights. - virtual std::pair get_utxo_pool_from(uint32_t from, uint32_t to) const = 0; - -#if ! defined(KTH_DB_READONLY) - virtual void prune_reorg_async() = 0; -#endif - - //virtual void set_database_flags() = 0; - - /////// Get the transaction of the given hash and its block height. - ////virtual transaction_ptr get_transaction(size_t& out_block_height, - //// hash_digest const& hash, bool require_confirmed) const = 0; - - // Writers. - // ------------------------------------------------------------------------ - -#if ! defined(KTH_DB_READONLY) - /// Insert a block to the blockchain, height is checked for existence. - // virtual bool insert(block_const_ptr block, size_t height, int) = 0; - virtual bool insert(block_const_ptr block, size_t height) = 0; - - /// Push an unconfirmed transaction to the tx table and index outputs. - virtual void push(transaction_const_ptr tx, dispatcher& dispatch, - complete_handler handler) = 0; - - /// Swap incoming and outgoing blocks, height is validated. - virtual void reorganize(const infrastructure::config::checkpoint& fork_point, - block_const_ptr_list_const_ptr incoming_blocks, - block_const_ptr_list_ptr outgoing_blocks, dispatcher& dispatch, - complete_handler handler) = 0; - -#endif //! defined(KTH_DB_READONLY) - - // Properties - // ------------------------------------------------------------------------ - - /// Get a reference to the chain state relative to the next block. - virtual domain::chain::chain_state::ptr chain_state() const = 0; - - /// Get a reference to the chain state relative to the next block. - virtual domain::chain::chain_state::ptr chain_state(branch::const_ptr branch) const = 0; - - virtual bool is_stale_fast() const = 0; -}; - -} // namespace kth::blockchain - -#endif diff --git a/src/blockchain/include/kth/blockchain/interface/safe_chain.hpp b/src/blockchain/include/kth/blockchain/interface/safe_chain.hpp deleted file mode 100644 index afec1ff9..00000000 --- a/src/blockchain/include/kth/blockchain/interface/safe_chain.hpp +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_BLOCKCHAIN_SAFE_CHAIN_HPP -#define KTH_BLOCKCHAIN_SAFE_CHAIN_HPP - -#include -#include -#include -#include -#include - -#include -// #include -#include - -#include -#include - -namespace kth::blockchain { - -/// This interface is thread safe. -/// A high level interface for encapsulation of the blockchain database. -/// Implementations are expected to be thread safe. -struct KB_API safe_chain { - using result_handler = handle0; - - /// Object fetch handlers. - using last_height_fetch_handler = handle1; - using block_height_fetch_handler = handle1; - using output_fetch_handler = handle1; - using spend_fetch_handler = handle1; - using history_fetch_handler = handle1; - using stealth_fetch_handler = handle1; - using transaction_index_fetch_handler = handle2; - - using confirmed_transactions_fetch_handler = handle1>; - // Smart pointer parameters must not be passed by reference. - using block_fetch_handler = std::function; - using block_header_txs_size_fetch_handler = std::function, uint64_t)>; - using block_hash_time_fetch_handler = std::function; - using merkle_block_fetch_handler = std::function; - using compact_block_fetch_handler = std::function; - using block_header_fetch_handler = std::function; - using transaction_fetch_handler = std::function; - using ds_proof_fetch_handler = std::function; - using transaction_unconfirmed_fetch_handler = std::function; - - using locator_block_headers_fetch_handler = std::function; - using block_locator_fetch_handler = std::function; - using inventory_fetch_handler = std::function; - - /// Subscription handlers. - using reorganize_handler = std::function; - using transaction_handler = std::function; - using ds_proof_handler = std::function; - - using for_each_tx_handler = std::function; - using mempool_mini_hash_map = std::unordered_map; - - // Startup and shutdown. - // ------------------------------------------------------------------------ - - virtual bool start() = 0; - virtual bool stop() = 0; - virtual bool close() = 0; - - // Node Queries. - // ------------------------------------------------------------------------ - - - virtual void fetch_block(size_t height, block_fetch_handler handler) const = 0; - - virtual void fetch_block(hash_digest const& hash, block_fetch_handler handler) const = 0; - - virtual void fetch_locator_block_hashes(get_blocks_const_ptr locator, hash_digest const& threshold, size_t limit, inventory_fetch_handler handler) const = 0; - - virtual void fetch_merkle_block(size_t height, merkle_block_fetch_handler handler) const = 0; - - virtual void fetch_merkle_block(hash_digest const& hash, merkle_block_fetch_handler handler) const = 0; - - virtual void fetch_compact_block(size_t height, compact_block_fetch_handler handler) const = 0; - - virtual void fetch_compact_block(hash_digest const& hash, compact_block_fetch_handler handler) const = 0; - - virtual void fetch_block_header_txs_size(hash_digest const& hash, block_header_txs_size_fetch_handler handler) const = 0; - - virtual void fetch_ds_proof(hash_digest const& hash, ds_proof_fetch_handler handler) const = 0; - - virtual void fetch_transaction(hash_digest const& hash, bool require_confirmed, transaction_fetch_handler handler) const = 0; - - virtual void fetch_transaction_position(hash_digest const& hash, bool require_confirmed, transaction_index_fetch_handler handler) const = 0; - - // virtual void for_each_transaction(size_t from, size_t to, for_each_tx_handler const& handler) const = 0; - - // virtual void for_each_transaction_non_coinbase(size_t from, size_t to, for_each_tx_handler const& handler) const = 0; - - virtual void fetch_locator_block_headers(get_headers_const_ptr locator, hash_digest const& threshold, size_t limit, locator_block_headers_fetch_handler handler) const = 0; - - virtual void fetch_block_locator(domain::chain::block::indexes const& heights, block_locator_fetch_handler handler) const = 0; - - virtual void fetch_last_height(last_height_fetch_handler handler) const = 0; - - virtual void fetch_block_header(size_t height, block_header_fetch_handler handler) const = 0; - - virtual void fetch_block_header(hash_digest const& hash, block_header_fetch_handler handler) const = 0; - - virtual bool get_block_hash(hash_digest& out_hash, size_t height) const = 0; - - virtual void fetch_block_height(hash_digest const& hash, block_height_fetch_handler handler) const = 0; - - virtual void fetch_block_hash_timestamp(size_t height, block_hash_time_fetch_handler handler) const = 0; - - // Server Queries. - //------------------------------------------------------------------------- - - virtual void fetch_spend(const domain::chain::output_point& outpoint, spend_fetch_handler handler) const = 0; - - virtual void fetch_history(short_hash const& address_hash, size_t limit, size_t from_height, history_fetch_handler handler) const = 0; - virtual void fetch_confirmed_transactions(short_hash const& address_hash, size_t limit, size_t from_height, confirmed_transactions_fetch_handler handler) const = 0; - - // virtual void fetch_stealth(binary const& filter, size_t from_height, stealth_fetch_handler handler) const = 0; - - // Transaction Pool. - //------------------------------------------------------------------------- - - virtual void fetch_template(merkle_block_fetch_handler handler) const = 0; - virtual void fetch_mempool(size_t count_limit, uint64_t minimum_fee, inventory_fetch_handler handler) const = 0; - - virtual std::vector get_mempool_transactions(std::vector const& payment_addresses, bool use_testnet_rules) const = 0; - - virtual std::vector get_mempool_transactions(std::string const& payment_address, bool use_testnet_rules) const = 0; - - virtual std::vector get_mempool_transactions_from_wallets(std::vector const& payment_addresses, bool use_testnet_rules) const = 0; - - virtual void fetch_unconfirmed_transaction(hash_digest const& hash, transaction_unconfirmed_fetch_handler handler) const = 0; - - virtual mempool_mini_hash_map get_mempool_mini_hash_map(domain::message::compact_block const& block) const = 0; - - virtual void fill_tx_list_from_mempool(domain::message::compact_block const& block, size_t& mempool_count, std::vector& txn_available, std::unordered_map const& shorttxids) const = 0; - - - // Filters. - //------------------------------------------------------------------------- - - virtual void filter_blocks(get_data_ptr message, result_handler handler) const = 0; - - virtual void filter_transactions(get_data_ptr message, result_handler handler) const = 0; - - // Subscribers. - //------------------------------------------------------------------------- - - virtual void subscribe_blockchain(reorganize_handler&& handler) = 0; - virtual void subscribe_transaction(transaction_handler&& handler) = 0; - virtual void subscribe_ds_proof(ds_proof_handler&& handler) = 0; - virtual void unsubscribe() = 0; - - - // Transaction Validation. - //----------------------------------------------------------------------------- - - virtual void transaction_validate(transaction_const_ptr tx, result_handler handler) const = 0; - - // Organizers. - //------------------------------------------------------------------------- - - virtual void organize(block_const_ptr block, result_handler handler) = 0; - virtual void organize(transaction_const_ptr tx, result_handler handler) = 0; - virtual void organize(double_spend_proof_const_ptr ds_proof, result_handler handler) = 0; - - // Properties - // ------------------------------------------------------------------------ - - virtual bool is_stale() const = 0; - - //TODO(Mario) temporary duplication - /// Get a determination of whether the block hash exists in the store. - virtual bool get_block_exists_safe(hash_digest const& block_hash) const = 0; - -}; - -} // namespace kth::blockchain - -#endif diff --git a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp index d3c4e6af..cb0e78ae 100644 --- a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp @@ -11,8 +11,6 @@ #include #include -#include -#include #include #include #include @@ -20,31 +18,44 @@ #include #include -#include + +#include + +#include +#include + +#include namespace kth::blockchain { +// Forward declaration +struct block_chain; + /// This class is thread safe. /// Organises blocks via the block pool to the blockchain. struct KB_API block_organizer { - using result_handler = handle0; + using executor_type = ::asio::any_io_executor; using ptr = std::shared_ptr; - using reorganize_handler = safe_chain::reorganize_handler; - using reorganize_subscriber = resubscriber; + using block_handler = std::function; + using block_broadcaster = broadcaster; /// Construct an instance. #if defined(KTH_WITH_MEMPOOL) - block_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool& mp); + block_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool& mp); #else - block_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions); + block_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions); #endif bool start(); bool stop(); - void organize(block_const_ptr block, result_handler handler); - void subscribe(reorganize_handler&& handler); - void unsubscribe(); + /// Organize a block - coroutine version + [[nodiscard]] + ::asio::awaitable organize(block_const_ptr block); + + [[nodiscard]] + block_broadcaster::channel_ptr subscribe(); + void unsubscribe(block_broadcaster::channel_ptr const& channel); /// Remove all message vectors that match block hashes. void filter(get_data_ptr message) const; @@ -56,24 +67,15 @@ struct KB_API block_organizer { // Utility. bool set_branch_height(branch::ptr branch); - // Verify sub-sequence. - void handle_check(code const& ec, block_const_ptr block, result_handler handler); - void handle_accept(code const& ec, branch::ptr branch, result_handler handler); - void handle_connect(code const& ec, branch::ptr branch, result_handler handler); - void organized(branch::ptr branch, result_handler handler); - #if ! defined(KTH_DB_READONLY) - void handle_reorganized(code const& ec, branch::const_ptr branch, block_const_ptr_list_ptr outgoing, result_handler handler); + ::asio::awaitable handle_reorganized(branch::const_ptr branch, block_const_ptr_list_ptr outgoing); #endif - void signal_completion(code const& ec); - #if defined(KTH_WITH_MEMPOOL) void populate_prevout_1(branch::const_ptr branch, domain::chain::output_point const& outpoint, bool require_confirmed) const; void populate_prevout_2(branch::const_ptr branch, domain::chain::output_point const& outpoint, local_utxo_set_t const& branch_utxo) const; void populate_transaction_inputs(branch::const_ptr branch, domain::chain::input::list const& inputs, local_utxo_set_t const& branch_utxo) const; void populate_transactions(branch::const_ptr branch, domain::chain::block const& block, local_utxo_set_t const& branch_utxo) const; - // void organize_mempool(branch::const_ptr branch, block_const_ptr_list_const_ptr const& incoming_blocks, block_const_ptr_list_ptr const& outgoing_blocks, local_utxo_set_t const& branch_utxo); void organize_mempool(branch::const_ptr branch, block_const_ptr_list_const_ptr const& incoming_blocks, block_const_ptr_list_ptr const& outgoing_blocks); #endif @@ -83,16 +85,16 @@ struct KB_API block_organizer { void notify(size_t branch_height, block_const_ptr_list_const_ptr branch, block_const_ptr_list_const_ptr original); // This must be protected by the implementation. - fast_chain& fast_chain_; + block_chain& chain_; // These are thread safe. prioritized_mutex& mutex_; std::atomic stopped_; - std::promise resume_; - dispatcher& dispatch_; + executor_type executor_; + size_t threads_; block_pool block_pool_; validate_block validator_; - reorganize_subscriber::ptr subscriber_; + block_broadcaster broadcaster_; #if defined(KTH_WITH_MEMPOOL) mining::mempool& mempool_; diff --git a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp new file mode 100644 index 00000000..b84cfe9c --- /dev/null +++ b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp @@ -0,0 +1,193 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_BLOCKCHAIN_HEADER_ORGANIZER_HPP +#define KTH_BLOCKCHAIN_HEADER_ORGANIZER_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace kth::blockchain { + +// Forward declaration +struct block_chain; + +/// Result of adding headers to the organizer +struct header_organize_result { + code error; + size_t headers_added{0}; + size_t cache_size{0}; + size_t cache_memory_bytes{0}; +}; + +/// Configuration for the header cache +struct header_cache_config { + /// Maximum memory to use for header cache (bytes) + /// Default: 256 MB + size_t max_cache_memory = 256 * 1024 * 1024; + + /// Memory overhead factor (for allocator overhead) + /// Default: 1.12 (~12% overhead for jemalloc) + double memory_overhead = 1.12; + + /// Auto-flush when cache reaches this percentage of max + /// Default: 0.9 (90%) + double auto_flush_threshold = 0.9; +}; + +/// Header organizer for headers-first sync. +/// Validates and caches headers during initial block download (IBD). +/// +/// ARCHITECTURE: +/// ------------- +/// The organizer maintains an in-memory cache of validated headers. +/// Headers are validated as they arrive and stored in the cache. +/// When flush() is called (or cache is full), headers are persisted to DB. +/// +/// This design allows: +/// 1. Fast header validation without DB round-trips +/// 2. Batch DB writes for efficiency +/// 3. Memory-aware caching with configurable limits +/// +/// THREAD SAFETY: +/// -------------- +/// All public methods are thread-safe (protected by mutex). +struct KB_API header_organizer { + using ptr = std::shared_ptr; + + /// Construct a header organizer. + /// @param[in] chain Reference to the blockchain. + /// @param[in] settings Blockchain settings. + /// @param[in] network The network type. + /// @param[in] config Cache configuration. + header_organizer(block_chain& chain, settings const& settings, + domain::config::network network, + header_cache_config config = {}); + + ~header_organizer(); + + // Non-copyable + header_organizer(header_organizer const&) = delete; + header_organizer& operator=(header_organizer const&) = delete; + + bool start(); + bool stop(); + + /// Initialize the organizer with current chain state. + /// Must be called before adding headers. + /// @param[in] current_height Current header height in DB. + /// @param[in] current_tip_hash Hash of current header tip. + /// @param[in] expected_headers Estimated number of headers to sync (for pre-allocation). + void initialize(size_t current_height, hash_digest const& current_tip_hash, + size_t expected_headers = 0); + + /// Add a batch of headers to the organizer. + /// Validates all headers and adds valid ones to the cache. + /// May auto-flush to DB if cache is getting full. + /// @param[in] headers The headers to add. + /// @return Result with error code and statistics. + [[nodiscard]] + header_organize_result add_headers(domain::message::header::list const& headers); + + /// Flush all cached headers to the database. + /// @return error::success or the storage error. + [[nodiscard]] + code flush(); + + /// Get the block hashes of all cached headers. + /// Useful for requesting blocks after headers are synced. + [[nodiscard]] + std::vector get_cached_hashes() const; + + /// Clear the cache without flushing to DB. + /// Use with caution - discards unwritten headers. + void clear_cache(); + + // ========================================================================= + // State queries + // ========================================================================= + + /// Get the current header tip height (DB + cache). + [[nodiscard]] + size_t header_height() const; + + /// Get the hash of the header tip. + [[nodiscard]] + hash_digest header_tip_hash() const; + + /// Get the number of headers in cache. + [[nodiscard]] + size_t cache_size() const; + + /// Get estimated memory usage of the cache. + [[nodiscard]] + size_t cache_memory() const; + + /// Check if cache has pending headers. + [[nodiscard]] + bool has_pending() const; + + /// Calculate optimal batch size based on available memory. + /// @param[in] items_needed Total headers we want to sync. + /// @return Optimal number of headers to cache. + [[nodiscard]] + size_t calculate_optimal_cache_size(size_t items_needed) const; + +protected: + [[nodiscard]] + bool stopped() const { + return stopped_; + } + +private: + // Validate a single header against expected previous + [[nodiscard]] + code validate(domain::chain::header const& header, size_t height, + hash_digest const& previous) const; + + // Estimate memory for a single header + [[nodiscard]] + static size_t estimated_header_size(); + + // Internal cache_memory without lock (caller must hold mutex_) + [[nodiscard]] + size_t cache_memory_impl() const; + + // Internal flush without lock (caller must hold mutex_) + [[nodiscard]] + code flush_impl(); + + // Check if we should auto-flush + [[nodiscard]] + bool should_auto_flush() const; + + // Members + block_chain& chain_; + std::atomic stopped_{false}; + validate_header validator_; + header_cache_config config_; + mutable std::mutex mutex_; + + // Chain state (protected by mutex_) + size_t db_header_height_{0}; // Height of headers in DB + hash_digest db_tip_hash_{null_hash}; // Hash of DB header tip + + // Cache state (protected by mutex_) + domain::chain::header::list header_cache_; + std::vector hash_cache_; // Parallel cache of hashes + hash_digest cache_tip_hash_{null_hash}; +}; + +} // namespace kth::blockchain + +#endif // KTH_BLOCKCHAIN_HEADER_ORGANIZER_HPP diff --git a/src/blockchain/include/kth/blockchain/pools/transaction_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/transaction_organizer.hpp index ac1e972d..0285a1e7 100644 --- a/src/blockchain/include/kth/blockchain/pools/transaction_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/transaction_organizer.hpp @@ -8,102 +8,101 @@ #include #include #include -#include +#include #include #include -#include -#include #include #include #include #include +#include #include -#include +#include + +#include +#include + +#include #if defined(KTH_WITH_MEMPOOL) #include - #endif namespace kth::blockchain { +using kth::awaitable_expected; + +// Forward declaration +struct block_chain; + /// This class is thread safe. /// Organises transactions via the transaction pool to the blockchain. struct KB_API transaction_organizer { - using result_handler = handle0; + using executor_type = ::asio::any_io_executor; using ptr = std::shared_ptr; - using transaction_handler = safe_chain::transaction_handler; - using ds_proof_handler = safe_chain::ds_proof_handler; - using inventory_fetch_handler = safe_chain::inventory_fetch_handler; - using merkle_block_fetch_handler = safe_chain::merkle_block_fetch_handler; - using ds_proof_fetch_handler = safe_chain::ds_proof_fetch_handler; - using transaction_subscriber = resubscriber; - using ds_proof_subscriber = resubscriber; - - /// Construct an instance. + using transaction_handler = std::function; + using ds_proof_handler = std::function; + using transaction_broadcaster = broadcaster; + using ds_proof_broadcaster = broadcaster; #if defined(KTH_WITH_MEMPOOL) - transaction_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings, mining::mempool& mp); + transaction_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings, mining::mempool& mp); #else - transaction_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings); + transaction_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings); #endif bool start(); bool stop(); - void organize(transaction_const_ptr tx, result_handler handler); - void organize(double_spend_proof_const_ptr ds_proof, result_handler handler); + [[nodiscard]] + ::asio::awaitable organize(transaction_const_ptr tx); + + [[nodiscard]] + ::asio::awaitable organize(double_spend_proof_const_ptr ds_proof); - void transaction_validate(transaction_const_ptr tx, result_handler handler) const; + [[nodiscard]] + ::asio::awaitable transaction_validate(transaction_const_ptr tx) const; - void subscribe(transaction_handler&& handler); - void subscribe_ds_proof(ds_proof_handler&& handler); - void unsubscribe(); - void unsubscribe_ds_proof(); + [[nodiscard]] + transaction_broadcaster::channel_ptr subscribe(); + [[nodiscard]] + ds_proof_broadcaster::channel_ptr subscribe_ds_proof(); + void unsubscribe(transaction_broadcaster::channel_ptr const& channel); + void unsubscribe_ds_proof(ds_proof_broadcaster::channel_ptr const& channel); - void fetch_template(merkle_block_fetch_handler) const; - void fetch_mempool(size_t maximum, inventory_fetch_handler) const; - void fetch_ds_proof(hash_digest const& hash, ds_proof_fetch_handler) const; + [[nodiscard]] + awaitable_expected> fetch_template() const; + + [[nodiscard]] + awaitable_expected fetch_mempool(size_t maximum) const; + + [[nodiscard]] + awaitable_expected fetch_ds_proof(hash_digest const& hash) const; protected: bool stopped() const; uint64_t price(transaction_const_ptr tx) const; private: - // Verify sub-sequence. - void handle_check(code const& ec, transaction_const_ptr tx, result_handler handler); - void handle_accept(code const& ec, transaction_const_ptr tx, result_handler handler); - void handle_connect(code const& ec, transaction_const_ptr tx, result_handler handler); - -#if ! defined(KTH_DB_READONLY) - void handle_pushed(code const& ec, transaction_const_ptr tx, result_handler handler); -#endif - - void signal_completion(code const& ec); - - void validate_handle_check(code const& ec, transaction_const_ptr tx, result_handler handler) const; - void validate_handle_accept(code const& ec, transaction_const_ptr tx, result_handler handler) const; - void validate_handle_connect(code const& ec, transaction_const_ptr tx, result_handler handler) const; - // Subscription. void notify(transaction_const_ptr tx); void notify_ds_proof(double_spend_proof_const_ptr tx); // This must be protected by the implementation. - fast_chain& fast_chain_; + block_chain& chain_; // These are thread safe. prioritized_mutex& mutex_; std::atomic stopped_; - std::promise resume_; settings const& settings_; - dispatcher& dispatch_; + executor_type executor_; + size_t threads_; transaction_pool transaction_pool_; validate_transaction validator_; - transaction_subscriber::ptr subscriber_; - ds_proof_subscriber::ptr ds_proof_subscriber_; + transaction_broadcaster broadcaster_; + ds_proof_broadcaster ds_proof_broadcaster_; #if defined(KTH_WITH_MEMPOOL) mining::mempool& mempool_; diff --git a/src/blockchain/include/kth/blockchain/pools/transaction_pool.hpp b/src/blockchain/include/kth/blockchain/pools/transaction_pool.hpp index e20e6bd5..557cad51 100644 --- a/src/blockchain/include/kth/blockchain/pools/transaction_pool.hpp +++ b/src/blockchain/include/kth/blockchain/pools/transaction_pool.hpp @@ -7,27 +7,29 @@ #include #include +#include #include -#include #include #include +#include + +#include + namespace kth::blockchain { +using kth::awaitable_expected; + /// TODO: this class is not implemented or utilized. struct KB_API transaction_pool { - using inventory_fetch_handler = safe_chain::inventory_fetch_handler; - using merkle_block_fetch_handler = safe_chain::merkle_block_fetch_handler; - transaction_pool(settings const& settings); - void fetch_template(merkle_block_fetch_handler) const; - void fetch_mempool(size_t maximum, inventory_fetch_handler) const; + [[nodiscard]] + awaitable_expected> fetch_template() const; -////private: -//// bool const reject_conflicts_; -//// const uint64_t minimum_fee_; + [[nodiscard]] + awaitable_expected fetch_mempool(size_t maximum) const; }; } // namespace kth::blockchain diff --git a/src/blockchain/include/kth/blockchain/populate/populate_base.hpp b/src/blockchain/include/kth/blockchain/populate/populate_base.hpp index cd414aa5..4723c542 100644 --- a/src/blockchain/include/kth/blockchain/populate/populate_base.hpp +++ b/src/blockchain/include/kth/blockchain/populate/populate_base.hpp @@ -9,28 +9,33 @@ #include #include -#include #include #include +#include + namespace kth::blockchain { +// Forward declaration +struct block_chain; + /// This class is NOT thread safe. class KB_API populate_base { protected: - using result_handler = handle0; + using executor_type = ::asio::any_io_executor; - populate_base(dispatcher& dispatch, fast_chain const& chain); + populate_base(executor_type executor, size_t threads, block_chain const& chain); - void populate_duplicate(size_t maximum_height, const domain::chain::transaction& tx, bool require_confirmed) const; + void populate_duplicate(size_t maximum_height, domain::chain::transaction const& tx, bool require_confirmed) const; void populate_pooled(domain::chain::transaction const& tx, uint32_t forks) const; void populate_prevout(size_t maximum_height, domain::chain::output_point const& outpoint, bool require_confirmed) const; - // This is thread safe. - dispatcher& dispatch_; + // Thread pool executor for parallel operations + executor_type executor_; + size_t threads_; // The store is protected by caller not invoking populate concurrently. - fast_chain const& fast_chain_; + block_chain const& chain_; }; } // namespace kth::blockchain diff --git a/src/blockchain/include/kth/blockchain/populate/populate_block.hpp b/src/blockchain/include/kth/blockchain/populate/populate_block.hpp index 29c93167..6bd05f88 100644 --- a/src/blockchain/include/kth/blockchain/populate/populate_block.hpp +++ b/src/blockchain/include/kth/blockchain/populate/populate_block.hpp @@ -7,46 +7,51 @@ #include +#include #include -#include #include #include #include +#include + #if defined(KTH_WITH_MEMPOOL) #include #endif namespace kth::blockchain { +// Forward declaration (already in populate_base.hpp, but explicit for clarity) +struct block_chain; + /// This class is NOT thread safe. struct KB_API populate_block : populate_base { public: using utxo_pool_t = database::internal_database::utxo_pool_t; #if defined(KTH_WITH_MEMPOOL) - populate_block(dispatcher& dispatch, fast_chain const& chain, bool relay_transactions, mining::mempool const& mp); + populate_block(executor_type executor, size_t threads, block_chain const& chain, bool relay_transactions, mining::mempool const& mp); #else - populate_block(dispatcher& dispatch, fast_chain const& chain, bool relay_transactions); + populate_block(executor_type executor, size_t threads, block_chain const& chain, bool relay_transactions); #endif /// Populate validation state for the top block. - void populate(branch::const_ptr branch, result_handler&& handler) const; + [[nodiscard]] + ::asio::awaitable populate(branch::const_ptr branch) const; protected: using branch_ptr = branch::const_ptr; void populate_coinbase(branch::const_ptr branch, block_const_ptr block) const; - ////void populate_duplicate(branch_ptr branch, const domain::chain::transaction& tx) const; utxo_pool_t get_reorg_subset_conditionally(size_t first_height, size_t& out_chain_top) const; void populate_from_reorg_subset(domain::chain::output_point const& outpoint, utxo_pool_t const& reorg_subset) const; void populate_transaction_inputs(branch::const_ptr branch, domain::chain::input::list const& inputs, size_t bucket, size_t buckets, size_t input_position, local_utxo_set_t const& branch_utxo, size_t first_height, size_t chain_top, utxo_pool_t const& reorg_subset) const; #if defined(KTH_WITH_MEMPOOL) - void populate_transactions(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo, mining::mempool::hash_index_t const& validated_txs, result_handler handler) const; + code populate_transactions_sync(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo, mining::mempool::hash_index_t const& validated_txs) const; #else - void populate_transactions(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo, result_handler handler) const; + code populate_transactions_sync(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo) const; #endif void populate_prevout(branch_ptr branch, domain::chain::output_point const& outpoint, local_utxo_set_t const& branch_utxo) const; diff --git a/src/blockchain/include/kth/blockchain/populate/populate_chain_state.hpp b/src/blockchain/include/kth/blockchain/populate/populate_chain_state.hpp index 9418e551..4f44771d 100644 --- a/src/blockchain/include/kth/blockchain/populate/populate_chain_state.hpp +++ b/src/blockchain/include/kth/blockchain/populate/populate_chain_state.hpp @@ -10,15 +10,17 @@ #include #include -#include #include #include namespace kth::blockchain { +// Forward declaration +struct block_chain; + /// This class is NOT thread safe. struct KB_API populate_chain_state { - populate_chain_state(fast_chain const& chain, settings const& settings, domain::config::network network); + populate_chain_state(block_chain const& chain, settings const& settings, domain::config::network network); /// Populate chain state for the tx pool (start). domain::chain::chain_state::ptr populate() const; @@ -66,7 +68,7 @@ struct KB_API populate_chain_state { // Populate is guarded against concurrent callers but because it uses the fast // chain it must not be invoked during chain writes. - fast_chain const& fast_chain_; + block_chain const& chain_; mutable shared_mutex mutex_; }; diff --git a/src/blockchain/include/kth/blockchain/populate/populate_transaction.hpp b/src/blockchain/include/kth/blockchain/populate/populate_transaction.hpp index 6a2435c5..fc53c555 100644 --- a/src/blockchain/include/kth/blockchain/populate/populate_transaction.hpp +++ b/src/blockchain/include/kth/blockchain/populate/populate_transaction.hpp @@ -8,31 +8,36 @@ #include #include -#include #include #include +#include + #if defined(KTH_WITH_MEMPOOL) #include #endif namespace kth::blockchain { +// Forward declaration (already in populate_base.hpp, but explicit for clarity) +struct block_chain; + /// This class is NOT thread safe. struct KB_API populate_transaction : populate_base { public: #if defined(KTH_WITH_MEMPOOL) - populate_transaction(dispatcher& dispatch, fast_chain const& chain, mining::mempool const& mp); + populate_transaction(executor_type executor, size_t threads, block_chain const& chain, mining::mempool const& mp); #else - populate_transaction(dispatcher& dispatch, fast_chain const& chain); + populate_transaction(executor_type executor, size_t threads, block_chain const& chain); #endif /// Populate validation state for the transaction. - void populate(transaction_const_ptr tx, result_handler&& handler) const; + [[nodiscard]] + ::asio::awaitable populate(transaction_const_ptr tx) const; protected: - void populate_inputs(transaction_const_ptr tx, size_t chain_height, size_t bucket, size_t buckets, result_handler handler) const; + code populate_inputs_sync(transaction_const_ptr tx, size_t chain_height, size_t bucket, size_t buckets) const; private: #if defined(KTH_WITH_MEMPOOL) diff --git a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp index f53911a7..800b6fe6 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp @@ -11,41 +11,52 @@ #include #include -#include #include #include #include #include +#include +#include + #if defined(KTH_WITH_MEMPOOL) #include #endif namespace kth::blockchain { +// Forward declaration +struct block_chain; + /// This class is NOT thread safe. struct KB_API validate_block { - using result_handler = handle0; + using executor_type = ::asio::any_io_executor; #if defined(KTH_WITH_MEMPOOL) - validate_block(dispatcher& dispatch, fast_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool const& mp); + validate_block(executor_type executor, size_t threads, block_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool const& mp); #else - validate_block(dispatcher& dispatch, fast_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions); + validate_block(executor_type executor, size_t threads, block_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions); #endif void start(); void stop(); - void check(block_const_ptr block, result_handler handler) const; - void accept(branch::const_ptr branch, result_handler handler) const; - void connect(branch::const_ptr branch, result_handler handler) const; + [[nodiscard]] + ::asio::awaitable check(block_const_ptr block) const; + + [[nodiscard]] + ::asio::awaitable accept(branch::const_ptr branch) const; + + [[nodiscard]] + ::asio::awaitable connect(branch::const_ptr branch) const; protected: - inline + [[nodiscard]] bool stopped() const { return stopped_; } + [[nodiscard]] float hit_rate() const; private: @@ -53,21 +64,24 @@ struct KB_API validate_block { using atomic_counter_ptr = std::shared_ptr; static - void dump(code const& ec, const domain::chain::transaction& tx, uint32_t input_index, uint32_t forks, size_t height); + void dump(code const& ec, domain::chain::transaction const& tx, uint32_t input_index, uint32_t forks, size_t height); + + // Synchronous helpers for parallel execution (called within asio::post) + [[nodiscard]] + code check_block_bucket(block_const_ptr block, size_t bucket, size_t buckets) const; + + [[nodiscard]] + code accept_transactions_bucket(block_const_ptr block, size_t bucket, size_t buckets, atomic_counter_ptr sigops, bool bip16, bool bip141) const; - void check_block(block_const_ptr block, size_t bucket, size_t buckets, result_handler handler) const; - void handle_checked(code const& ec, block_const_ptr block, result_handler handler) const; - void handle_populated(code const& ec, block_const_ptr block, result_handler handler) const; - void accept_transactions(block_const_ptr block, size_t bucket, size_t buckets, atomic_counter_ptr sigops, bool bip16, bool bip141, result_handler handler) const; - void handle_accepted(code const& ec, block_const_ptr block, atomic_counter_ptr sigops, bool bip141, result_handler handler) const; - void connect_inputs(block_const_ptr block, size_t bucket, size_t buckets, result_handler handler) const; - void handle_connected(code const& ec, block_const_ptr block, result_handler handler) const; + [[nodiscard]] + code connect_inputs_bucket(block_const_ptr block, size_t bucket, size_t buckets) const; // These are thread safe. std::atomic stopped_; - fast_chain const& fast_chain_; + block_chain const& chain_; domain::config::network network_; - dispatcher& priority_dispatch_; + executor_type executor_; + size_t threads_; mutable atomic_counter hits_; mutable atomic_counter queries_; diff --git a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp new file mode 100644 index 00000000..f7337579 --- /dev/null +++ b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp @@ -0,0 +1,101 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_BLOCKCHAIN_VALIDATE_HEADER_HPP +#define KTH_BLOCKCHAIN_VALIDATE_HEADER_HPP + +#include +#include + +#include +#include +#include + +namespace kth::blockchain { + +/// Header validation for headers-first sync. +/// This class performs header validation without requiring full chain state, +/// making it suitable for initial block download (IBD) where we validate +/// headers before downloading full blocks. +/// +/// Validation levels: +/// 1. check() - Context-free checks (PoW, timestamp not too far in future) +/// 2. accept() - Chain-context checks (checkpoints, chain continuity) +/// +/// Note: Difficulty validation (work_required) is NOT done here because it +/// requires building full chain_state with historical data. During IBD, +/// difficulty is validated when blocks are organized. +struct KB_API validate_header { + using checkpoint = infrastructure::config::checkpoint; + using checkpoint_list = infrastructure::config::checkpoint::list; + + /// Construct a header validator. + /// @param[in] settings Blockchain settings (checkpoints, forks). + /// @param[in] network The network type (mainnet, testnet, etc). + validate_header(settings const& settings, domain::config::network network); + + /// Context-free validation (PoW + timestamp). + /// Validates: + /// - Proof of work is valid for the claimed difficulty (bits) + /// - Timestamp is not too far in the future (2 hours) + /// + /// @param[in] header The header to validate. + /// @return error::success or the validation error. + [[nodiscard]] + code check(domain::chain::header const& header) const; + + /// Chain-context validation (checkpoints + continuity). + /// Validates: + /// - Header hash matches checkpoint at this height (if one exists) + /// - Header does not conflict with any checkpoint + /// - Previous block hash matches expected (chain continuity) + /// + /// @param[in] header The header to validate. + /// @param[in] height The height of this header. + /// @param[in] previous Expected previous block hash. + /// @return error::success or the validation error. + [[nodiscard]] + code accept(domain::chain::header const& header, size_t height, + hash_digest const& previous) const; + + /// Combined check + accept for convenience. + /// @param[in] header The header to validate. + /// @param[in] height The height of this header. + /// @param[in] previous Expected previous block hash. + /// @return error::success or the first validation error. + [[nodiscard]] + code validate(domain::chain::header const& header, size_t height, + hash_digest const& previous) const; + + /// Check if a height is under checkpoint protection. + /// Headers under checkpoint can skip some validation. + [[nodiscard]] + bool is_under_checkpoint(size_t height) const; + + /// Check if height has a checkpoint defined. + [[nodiscard]] + bool is_checkpoint_height(size_t height) const; + + /// Get the checkpoint hash at a given height (if exists). + [[nodiscard]] + std::optional checkpoint_hash(size_t height) const; + +private: + /// Check if header hash conflicts with a checkpoint at this height. + [[nodiscard]] + bool is_checkpoint_conflict(hash_digest const& hash, size_t height) const; + + /// Get the highest checkpoint height. + [[nodiscard]] + size_t last_checkpoint_height() const; + + // Configuration + checkpoint_list const checkpoints_; + domain::config::network const network_; + bool const retarget_; // Whether PoW retargeting is enabled (mainnet=true) +}; + +} // namespace kth::blockchain + +#endif // KTH_BLOCKCHAIN_VALIDATE_HEADER_HPP diff --git a/src/blockchain/include/kth/blockchain/validate/validate_transaction.hpp b/src/blockchain/include/kth/blockchain/validate/validate_transaction.hpp index 0a7b30a4..575fddad 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_transaction.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_transaction.hpp @@ -9,35 +9,44 @@ #include #include -#include #include #include #include #include +#include +#include + #if defined(KTH_WITH_MEMPOOL) #include #endif namespace kth::blockchain { +// Forward declaration +struct block_chain; + /// This class is NOT thread safe. struct KB_API validate_transaction { - // using result_handler = handle0; - using result_handler = handle0; + using executor_type = ::asio::any_io_executor; #if defined(KTH_WITH_MEMPOOL) - validate_transaction(dispatcher& dispatch, fast_chain const& chain, settings const& settings, mining::mempool const& mp); + validate_transaction(executor_type executor, size_t threads, block_chain const& chain, settings const& settings, mining::mempool const& mp); #else - validate_transaction(dispatcher& dispatch, fast_chain const& chain, settings const& settings); + validate_transaction(executor_type executor, size_t threads, block_chain const& chain, settings const& settings); #endif void start(); void stop(); - void check(transaction_const_ptr tx, result_handler handler) const; - void accept(transaction_const_ptr tx, result_handler handler) const; - void connect(transaction_const_ptr tx, result_handler handler) const; + [[nodiscard]] + ::asio::awaitable check(transaction_const_ptr tx) const; + + [[nodiscard]] + ::asio::awaitable accept(transaction_const_ptr tx) const; + + [[nodiscard]] + ::asio::awaitable connect(transaction_const_ptr tx) const; protected: inline @@ -46,14 +55,14 @@ struct KB_API validate_transaction { } private: - void handle_populated(code const& ec, transaction_const_ptr tx, result_handler handler) const; - void connect_inputs(transaction_const_ptr tx, size_t bucket, size_t buckets, result_handler handler) const; + code connect_inputs_sync(transaction_const_ptr tx, size_t bucket, size_t buckets) const; // These are thread safe. std::atomic stopped_; bool const retarget_; - fast_chain const& fast_chain_; - dispatcher& dispatch_; + block_chain const& chain_; + executor_type executor_; + size_t threads_; // Caller must not invoke accept/connect concurrently. populate_transaction transaction_populator_; diff --git a/src/blockchain/src/interface/block_chain.cpp b/src/blockchain/src/interface/block_chain.cpp index e63ff4b6..08335974 100644 --- a/src/blockchain/src/interface/block_chain.cpp +++ b/src/blockchain/src/interface/block_chain.cpp @@ -5,11 +5,12 @@ #include #include +#include #include #include +#include #include #include - #include #include #include @@ -26,8 +27,15 @@ #include #include +#include +#include +#include +#include +#include +#include + namespace kth { -//TODO: remove from here + time_t floor_subtract(time_t left, time_t right) { static auto const floor = (std::numeric_limits::min)(); return right >= left ? floor : left - right; @@ -38,7 +46,6 @@ time_t floor_subtract(time_t left, time_t right) { namespace kth::blockchain { using spent_value_type = std::pair; -//using spent_container = std::vector; using spent_container = std::unordered_set; } // namespace kth::blockchain @@ -76,8 +83,15 @@ using namespace std::placeholders; static auto const hour_seconds = 3600u; -block_chain::block_chain(threadpool& pool, blockchain::settings const& chain_settings - , database::settings const& database_settings, domain::config::network network, bool relay_transactions /* = true*/) +// ============================================================================= +// CONSTRUCTION +// ============================================================================= + +block_chain::block_chain(threadpool& pool, + blockchain::settings const& chain_settings, + database::settings const& database_settings, + domain::config::network network, + bool relay_transactions) : stopped_(true) , settings_(chain_settings) , notify_limit_seconds_(chain_settings.notify_limit_hours * hour_seconds) @@ -85,667 +99,977 @@ block_chain::block_chain(threadpool& pool, blockchain::settings const& chain_set , database_(database_settings) , validation_mutex_(relay_transactions) , priority_pool_(thread_ceiling(chain_settings.cores)) - , dispatch_(priority_pool_, NAME "_priority") - #if defined(KTH_WITH_MEMPOOL) , mempool_(chain_settings.mempool_max_template_size, chain_settings.mempool_size_multiplier) - , transaction_organizer_(validation_mutex_, dispatch_, pool, *this, chain_settings, mempool_) - , block_organizer_(validation_mutex_, dispatch_, pool, *this, chain_settings, network, relay_transactions, mempool_) + , transaction_organizer_(validation_mutex_, priority_pool_.get_executor(), priority_pool_.size(), priority_pool_, *this, chain_settings, mempool_) + , block_organizer_(validation_mutex_, priority_pool_.get_executor(), priority_pool_.size(), priority_pool_, *this, chain_settings, network, relay_transactions, mempool_) #else - , transaction_organizer_(validation_mutex_, dispatch_, pool, *this, chain_settings) - , block_organizer_(validation_mutex_, dispatch_, pool, *this, chain_settings, network, relay_transactions) + , transaction_organizer_(validation_mutex_, priority_pool_.get_executor(), priority_pool_.size(), priority_pool_, *this, chain_settings) + , block_organizer_(validation_mutex_, priority_pool_.get_executor(), priority_pool_.size(), priority_pool_, *this, chain_settings, network, relay_transactions) #endif -{} - -// ============================================================================ -// FAST CHAIN -// ============================================================================ - -// Readers. -// ---------------------------------------------------------------------------- - -uint32_t get_clock_now() { - auto const now = std::chrono::high_resolution_clock::now(); - return uint32_t(std::chrono::duration_cast(now.time_since_epoch()).count()); +{ + spdlog::debug("[blockchain] block_chain constructor completed successfully"); } -bool block_chain::get_output(domain::chain::output& out_output, size_t& out_height, - uint32_t& out_median_time_past, bool& out_coinbase, - const domain::chain::output_point& outpoint, size_t branch_height, - bool require_confirmed) const { +block_chain::~block_chain() { + (void)close(); +} - auto const tx = database_.internal_db().get_transaction(outpoint.hash(), branch_height); +// ============================================================================= +// LIFECYCLE +// ============================================================================= - if ( ! tx.is_valid()) return false; +bool block_chain::start() { + stopped_ = false; - out_height = tx.height(); - out_coinbase = tx.position() == 0; - out_median_time_past = tx.median_time_past(); - out_output = tx.transaction().outputs()[outpoint.index()]; + if ( ! database_.open()) { + spdlog::error("[blockchain] Failed to open database."); + return false; + } - return true; -} + pool_state_ = chain_state_populator_.populate(); + if ( ! pool_state_) { + spdlog::error("[blockchain] Failed to initialize chain state."); + return false; + } -bool block_chain::get_transaction_position(size_t& out_height, size_t& out_position, hash_digest const& hash, bool require_confirmed) const { + if ( ! transaction_organizer_.start()) { + spdlog::error("[blockchain] Failed to start transaction organizer."); + return false; + } - auto const result = database_.internal_db().get_transaction(hash, max_size_t); + if ( ! block_organizer_.start()) { + spdlog::error("[blockchain] Failed to start block organizer."); + return false; + } - if ( result.is_valid() ) { - out_height = result.height(); - out_position = result.position(); - return true; + // Load all headers from database into header_index + // This allows resuming sync from where we left off + auto const heights = get_last_heights(); + if ( ! heights) { + spdlog::error("[blockchain] Failed to get last heights from database."); + return false; } - if (require_confirmed ) return false; + auto const [header_height, block_height] = *heights; + spdlog::info("[blockchain] Database state: header_height={}, block_height={}", header_height, block_height); - auto const result2 = database_.internal_db().get_transaction_unconfirmed(hash); - if ( ! result2.is_valid() ) return false; + if (header_height == 0) { + // Only genesis in DB - just add genesis to index + auto const genesis = get_header(0); + if (genesis) { + auto const hash = genesis->hash(); + auto const [inserted, idx, capacity_warning] = header_index_.add(hash, *genesis); + if ( ! inserted) { + spdlog::error("[blockchain] Failed to initialize header index with genesis block."); + return false; + } + spdlog::info("[blockchain] Header index initialized with genesis: {}", encode_hash(hash)); + } + } else { + // Load all headers from DB into header_index + spdlog::info("[blockchain] Loading {} headers from database into header_index...", header_height + 1); - out_height = result2.height(); - out_position = position_max; - return true; -} + auto const load_start = std::chrono::steady_clock::now(); -#if ! defined(KTH_DB_READONLY) -void block_chain::prune_reorg_async() { - if ( ! is_stale()) { - dispatch_.concurrent([this](){ - database_.prune_reorg(); - }); - } -} -#endif // ! defined(KTH_DB_READONLY) + // Load in batches to avoid memory spikes + constexpr size_t batch_size = 10000; + size_t loaded = 0; -bool block_chain::get_block_exists(hash_digest const& block_hash) const { - return database_.internal_db().get_header(block_hash).first.is_valid(); -} + for (size_t from = 0; from <= header_height; from += batch_size) { + auto const to = std::min(from + batch_size - 1, header_height); + auto const headers_result = get_headers(from, to); -bool block_chain::get_block_exists_safe(hash_digest const& block_hash) const { - return get_block_exists(block_hash); -} + if ( ! headers_result) { + spdlog::error("[blockchain] Failed to load headers from {} to {}", from, to); + return false; + } -bool block_chain::get_block_hash(hash_digest& out_hash, size_t height) const { - auto const result = database_.internal_db().get_header(height); - if ( ! result.is_valid()) return false; - out_hash = result.hash(); - return true; -} + size_t height = from; + for (auto const& header : *headers_result) { + auto const hash = header.hash(); + auto const [inserted, idx, capacity_warning] = header_index_.add(hash, header); + if ( ! inserted && height > 0) { + // Genesis might already be added, ignore that case + spdlog::warn("[blockchain] Failed to add header at height {} to index", height); + } + ++height; + ++loaded; + } -bool block_chain::get_branch_work(uint256_t& out_work, uint256_t const& maximum, size_t from_height) const { - size_t top; - if ( ! get_last_height(top)) return false; + // Log progress every 100k headers + if (loaded % 100000 < batch_size && loaded > 0) { + spdlog::info("[blockchain] Loaded {}/{} headers into index...", loaded, header_height + 1); + } + } - out_work = 0; - for (uint32_t height = from_height; height <= top && out_work < maximum; ++height) { - auto const result = database_.internal_db().get_header(height); - if ( ! result.is_valid()) return false; - out_work += domain::chain::header::proof(result.bits()); + auto const elapsed = std::chrono::steady_clock::now() - load_start; + auto const elapsed_ms = std::chrono::duration_cast(elapsed).count(); + spdlog::info("[blockchain] Loaded {} headers into header_index in {}ms", loaded, elapsed_ms); } return true; } -bool block_chain::get_header(domain::chain::header& out_header, size_t height) const { - out_header = database_.internal_db().get_header(height); - return out_header.is_valid(); -} +bool block_chain::stop() { + stopped_ = true; -std::optional block_chain::get_header_and_abla_state(size_t height) const { - return database_.internal_db().get_header_and_abla_state(height); -} + validation_mutex_.lock_high_priority(); + auto result = transaction_organizer_.stop() && block_organizer_.stop(); + priority_pool_.stop(); + validation_mutex_.unlock_high_priority(); -domain::chain::header::list block_chain::get_headers(size_t from, size_t to) const { - return database_.internal_db().get_headers(from, to); + return result; } -bool block_chain::get_height(size_t& out_height, hash_digest const& block_hash) const { - auto result = database_.internal_db().get_header(block_hash); - if ( ! result.first.is_valid()) return false; - out_height = result.second; - return true; +bool block_chain::close() { + auto const result = stop(); + priority_pool_.join(); + return result && database_.close(); } -bool block_chain::get_bits(uint32_t& out_bits, size_t height) const { - auto result = database_.internal_db().get_header(height); - if ( ! result.is_valid()) return false; - out_bits = result.bits(); - return true; +bool block_chain::stopped() const { + return stopped_; } -bool block_chain::get_timestamp(uint32_t& out_timestamp, size_t height) const { - auto result = database_.internal_db().get_header(height); - if ( ! result.is_valid()) return false; - out_timestamp = result.timestamp(); - return true; -} +// ============================================================================= +// ORGANIZERS (Core blockchain operations) +// ============================================================================= -bool block_chain::get_version(uint32_t& out_version, size_t height) const { - auto result = database_.internal_db().get_header(height); - if ( ! result.is_valid()) return false; - out_version = result.version(); - return true; +::asio::awaitable block_chain::organize(block_const_ptr block, bool headers_pre_validated) { + co_return co_await block_organizer_.organize(block, headers_pre_validated); } -bool block_chain::get_last_height(size_t& out_height) const { - uint32_t temp; - auto const res = database_.internal_db().get_last_height(temp); - out_height = temp; - return succeed(res); +::asio::awaitable block_chain::organize(transaction_const_ptr tx) { + co_return co_await transaction_organizer_.organize(tx); } -bool block_chain::get_utxo(domain::chain::output& out_output, size_t& out_height, uint32_t& out_median_time_past, bool& out_coinbase, domain::chain::output_point const& outpoint, size_t branch_height) const { - auto entry = database_.internal_db().get_utxo(outpoint); - if ( ! entry.is_valid()) return false; - if (entry.height() > branch_height) return false; - - out_output = entry.output(); - out_height = entry.height(); - out_median_time_past = entry.median_time_past(); - out_coinbase = entry.coinbase(); - - return true; +::asio::awaitable block_chain::organize(double_spend_proof_const_ptr ds_proof) { + co_return co_await transaction_organizer_.organize(ds_proof); } -std::pair block_chain::get_utxo_pool_from(uint32_t from, uint32_t to) const { - auto p = database_.internal_db().get_utxo_pool_from(from, to); - - if (p.first != result_code::success) { - return {false, std::move(p.second)}; +::asio::awaitable block_chain::organize_header(header_const_ptr header) { + if (stopped()) { + co_return error::service_stopped; } - return {true, std::move(p.second)}; -} - -// Writers -// ---------------------------------------------------------------------------- -#if ! defined(KTH_DB_READONLY) -// bool block_chain::insert(block_const_ptr block, size_t height, int) { -bool block_chain::insert(block_const_ptr block, size_t height) { - return database_.insert(*block, height) == error::success; -} + // Get current header height + auto const heights = get_last_heights(); + if ( ! heights) { + co_return error::operation_failed; + } -void block_chain::push(transaction_const_ptr tx, dispatcher&, result_handler handler) { + auto const next_height = heights->first + 1; // header_height + 1 - //TODO(kth): dissabled this tx cache because we don't want special treatment for the last txn, it affects the explorer rpc methods - //last_transaction_.store(tx); + // Store header in database with ABLA state = 0 + // The correct ABLA state will be set when the full block arrives via push_block + auto const ec = database_.push_header(*header, next_height); + if (ec) { + co_return ec; + } - // Transaction push is currently sequential so dispatch is not used. - handler(database_.push(*tx, chain_state()->enabled_forks())); + co_return error::success; } -#endif // ! defined(KTH_DB_READONLY) - -#ifdef KTH_DB_TRANSACTION_UNCONFIRMED -void block_chain::fetch_unconfirmed_transaction(hash_digest const& hash, transaction_unconfirmed_fetch_handler handler) const { +code block_chain::organize_headers_batch(domain::chain::header::list const& headers, size_t start_height) { if (stopped()) { - handler(error::service_stopped, nullptr); - return; + return error::service_stopped; } - auto const result = database_.transactions_unconfirmed().get(hash); - - if ( ! result) { - handler(error::not_found, nullptr); - return; + if (headers.empty()) { + return error::success; } - auto const tx = std::make_shared(result.transaction()); - handler(error::success, tx); + return database_.push_headers_batch(headers, start_height); } -#endif // KTH_DB_TRANSACTION_UNCONFIRMED #if ! defined(KTH_DB_READONLY) -void block_chain::reorganize(const infrastructure::config::checkpoint& fork_point, - block_const_ptr_list_const_ptr incoming_blocks, - block_const_ptr_list_ptr outgoing_blocks, dispatcher& dispatch, - result_handler handler) { + +awaitable_expected block_chain::reorganize( + infrastructure::config::checkpoint const& fork_point, + block_const_ptr_list_const_ptr incoming_blocks) { + if (incoming_blocks->empty()) { - handler(error::reorganize_empty_blocks); - return; + co_return std::unexpected(error::reorganize_empty_blocks); } - // The top (back) block is used to update the chain state. - auto const complete = std::bind(&block_chain::handle_reorganize, this, _1, incoming_blocks->back(), handler); - database_.reorganize(fork_point, incoming_blocks, outgoing_blocks, dispatch, complete); -} + auto result = co_await database_.reorganize(priority_pool_.get_executor(), fork_point, incoming_blocks); -void block_chain::handle_reorganize(code const& ec, block_const_ptr top, result_handler handler) { - if (ec) { - handler(ec); - return; + if ( ! result.has_value()) { + co_return std::unexpected(result.error()); } + auto const& top = incoming_blocks->back(); if ( ! top->validation.state) { - handler(error::chain_state_invalid); - return; + co_return std::unexpected(error::chain_state_invalid); } set_chain_state(top->validation.state); last_block_.store(top); - handler(error::success); + co_return std::move(result.value()); +} + +::asio::awaitable block_chain::push(transaction_const_ptr tx) { + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(priority_pool_.get_executor(), 1); + + ::asio::post(priority_pool_.get_executor(), [this, tx, channel]() { + auto const result = push_sync(tx); + channel->try_send(std::error_code{}, result); + }); + + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return error::operation_failed; + } + co_return result; +} + +code block_chain::push_sync(transaction_const_ptr tx) { + return database_.push(*tx, chain_state()->enabled_forks()); +} + +bool block_chain::insert(block_const_ptr block, size_t height) { + return database_.insert(*block, height) == error::success; +} + +void block_chain::prune_reorg_async() { + if ( ! is_stale()) { + ::asio::post(priority_pool_.get_executor(), [this]() { + database_.prune_reorg(); + }); + } } #endif // ! defined(KTH_DB_READONLY) -// Properties. -// ---------------------------------------------------------------------------- +// ============================================================================= +// CHAIN STATE +// ============================================================================= -// For tx validator, call only from inside validate critical section. domain::chain::chain_state::ptr block_chain::chain_state() const { - // Critical Section - /////////////////////////////////////////////////////////////////////////// shared_lock lock(pool_state_mutex_); - - // Initialized on start and updated after each successful organization. return pool_state_; - /////////////////////////////////////////////////////////////////////////// } -// For block validator, call only from inside validate critical section. domain::chain::chain_state::ptr block_chain::chain_state(branch::const_ptr branch) const { - // Promote from cache if branch is same height as pool (most typical). - // Generate from branch/store if the promotion is not successful. - // If the organize is successful pool state will be updated accordingly. return chain_state_populator_.populate(chain_state(), branch); } -// private. code block_chain::set_chain_state(domain::chain::chain_state::ptr previous) { - // Critical Section - /////////////////////////////////////////////////////////////////////////// unique_lock lock(pool_state_mutex_); - pool_state_ = chain_state_populator_.populate(previous); return pool_state_ ? error::success : error::pool_state_failed; - /////////////////////////////////////////////////////////////////////////// } -// ============================================================================ -// SAFE CHAIN -// ============================================================================ +// ============================================================================= +// SUBSCRIPTIONS +// ============================================================================= -// Startup and shutdown. -// ---------------------------------------------------------------------------- +block_chain::block_channel_ptr block_chain::subscribe_blockchain() { + return block_organizer_.subscribe(); +} -bool block_chain::start() { - stopped_ = false; +block_chain::transaction_channel_ptr block_chain::subscribe_transaction() { + return transaction_organizer_.subscribe(); +} - if ( ! database_.open()) { - spdlog::error("[blockchain] Failed to open database."); - return false; - } +block_chain::ds_proof_channel_ptr block_chain::subscribe_ds_proof() { + return transaction_organizer_.subscribe_ds_proof(); +} - //switch to fast mode if the database is stale - //set_database_flags(); +void block_chain::unsubscribe_blockchain(block_channel_ptr const& channel) { + block_organizer_.unsubscribe(channel); +} - // Initialize chain state after database start but before organizers. - pool_state_ = chain_state_populator_.populate(); - if ( ! pool_state_) { - spdlog::error("[blockchain] Failed to initialize chain state."); - return false; - } +void block_chain::unsubscribe_transaction(transaction_channel_ptr const& channel) { + transaction_organizer_.unsubscribe(channel); +} - auto const tx_org_started = transaction_organizer_.start(); - if ( ! tx_org_started) { - spdlog::error("[blockchain] Failed to start transaction organizer."); - return false; - } +void block_chain::unsubscribe_ds_proof(ds_proof_channel_ptr const& channel) { + transaction_organizer_.unsubscribe_ds_proof(channel); +} - auto const blk_org_started = block_organizer_.start(); - if ( ! blk_org_started) { - spdlog::error("[blockchain] Failed to start block organizer."); - return false; - } - return true; +// ============================================================================= +// VALIDATION +// ============================================================================= + +::asio::awaitable block_chain::transaction_validate(transaction_const_ptr tx) const { + co_return co_await transaction_organizer_.transaction_validate(tx); } -bool block_chain::stop() { - stopped_ = true; +// ============================================================================= +// PROPERTIES +// ============================================================================= - // Critical Section - /////////////////////////////////////////////////////////////////////////// - validation_mutex_.lock_high_priority(); +bool block_chain::is_stale() const { + if (notify_limit_seconds_ == 0) { + return false; + } - // This cannot call organize or stop (lock safe). - auto result = transaction_organizer_.stop() && block_organizer_.stop(); + auto const top = last_block_.load(); - // The priority pool must not be stopped while organizing. - priority_pool_.stop(); + uint32_t last_timestamp = 0; + if ( ! top) { + auto const heights = get_last_heights(); + if (heights) { + auto const last_height = heights->second; // block_height + auto const last_header = get_header(last_height); + if (last_header) { + last_timestamp = last_header->timestamp(); + } + } + } - validation_mutex_.unlock_high_priority(); - /////////////////////////////////////////////////////////////////////////// - return result; + auto const timestamp = top ? top->header().timestamp() : last_timestamp; + return timestamp < floor_subtract(zulu_time(), notify_limit_seconds_); } -// Close is idempotent and thread safe. -// Optional as the blockchain will close on destruct. -bool block_chain::close() { - auto const result = stop(); - priority_pool_.join(); - return result && database_.close(); +settings const& block_chain::chain_settings() const { + return settings_; } -block_chain::~block_chain() { - close(); +block_chain::executor_type block_chain::executor() const { + return priority_pool_.get_executor(); } -// Queries. -// ---------------------------------------------------------------------------- -// Blocks are and transactions returned const because they don't change and -// this eliminates the need to copy the cached items. +#if defined(KTH_WITH_MEMPOOL) +std::pair, uint64_t> block_chain::get_block_template() const { + return mempool_.get_block_template(); +} +#endif -void block_chain::fetch_block(size_t height, - block_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0); - return; +// ============================================================================= +// DATABASE READERS (Low-level, NOT thread safe) +// ============================================================================= + +// bool block_chain::get_last_height(size_t& out_height) const { +// auto result = database_.internal_db().get_last_heights(); +// if ( ! result) { +// return false; +// } +// out_height = result->first; // header_height +// return true; +// } + +std::expected, database::result_code> block_chain::get_last_heights() const { + auto result = database_.internal_db().get_last_heights(); + if ( ! result) { + return std::unexpected(result.error()); } + auto const& [header_height, block_height] = *result; + return std::pair{size_t(header_height), size_t(block_height)}; +} - auto const cached = last_block_.load(); +std::expected block_chain::get_header(size_t height) const { + return database_.internal_db().get_header(height); +} - // Try the cached block first. - if (cached && cached->validation.state && - cached->validation.state->height() == height) { - handler(error::success, cached, height); - return; - } +std::expected block_chain::get_header_and_abla_state(size_t height) const { + return database_.internal_db().get_header_and_abla_state(height); +} - auto const block_result = database_.internal_db().get_block(height); +std::expected block_chain::get_headers(size_t from, size_t to) const { + return database_.internal_db().get_headers(from, to); +} - if ( ! block_result.is_valid()) { - handler(error::not_found, nullptr, 0); - return; +std::expected block_chain::get_height(hash_digest const& block_hash) const { + auto result = database_.internal_db().get_header(block_hash); + if ( ! result) { + return std::unexpected(result.error()); } + return result->second; +} - auto const result = std::make_shared(block_result); - - handler(error::success, result, height); +std::expected block_chain::get_bits(size_t height) const { + auto result = database_.internal_db().get_header(height); + if ( ! result) { + return std::unexpected(result.error()); + } + return result->bits(); } -void block_chain::fetch_block(hash_digest const& hash, - block_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0); - return; +std::expected block_chain::get_timestamp(size_t height) const { + auto result = database_.internal_db().get_header(height); + if ( ! result) { + return std::unexpected(result.error()); } + return result->timestamp(); +} - auto const cached = last_block_.load(); +std::expected block_chain::get_version(size_t height) const { + auto result = database_.internal_db().get_header(height); + if ( ! result) { + return std::unexpected(result.error()); + } + return result->version(); +} - // Try the cached block first. - if (cached && cached->validation.state && cached->hash() == hash) { - handler(error::success, cached, cached->validation.state->height()); - return; +std::expected block_chain::get_block_hash(size_t height) const { + auto const result = database_.internal_db().get_header(height); + if ( ! result) { + return std::unexpected(result.error()); } + return result->hash(); +} - auto const block_result = database_.internal_db().get_block(hash); +bool block_chain::header_exists(hash_digest const& block_hash) const { + return database_.internal_db().get_header(block_hash).has_value(); +} - if ( ! block_result.first.is_valid()) { - handler(error::not_found, nullptr, 0); - return; +bool block_chain::block_exists(hash_digest const& block_hash) const { + // Check if full block exists (not just header) + // With headers-first sync, headers may exist without full blocks + auto const header_result = database_.internal_db().get_header(block_hash); + if (!header_result) { + return false; // Header doesn't exist, so block doesn't exist } - auto const height = block_result.second; + // Header exists - check if we have the full block + auto const heights = database_.internal_db().get_last_heights(); + if (!heights) { + return false; + } - auto const result = std::make_shared(block_result.first); + auto const [header_height, block_height] = *heights; + auto const this_block_height = header_result->second; - handler(error::success, result, height); + // Block exists only if its height <= block_height + return this_block_height <= block_height; } -void block_chain::fetch_block_header_txs_size(hash_digest const& hash, - block_header_txs_size_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0, std::make_shared(hash_list()),0); - return; +std::expected block_chain::get_branch_work(uint256_t const& maximum, size_t from_height) const { + auto const heights = get_last_heights(); + if ( ! heights) { + return std::unexpected(heights.error()); } + // Use block_height (not header_height) for work comparison + // With headers-first sync, we may have headers without full blocks + auto const top = heights->second; // block_height - auto const block_result = database_.internal_db().get_block(hash); - - if ( ! block_result.first.is_valid()) { - handler(error::not_found, nullptr, 0, std::make_shared(hash_list()),0); - return; + uint256_t out_work = 0; + for (uint32_t height = from_height; height <= top && out_work < maximum; ++height) { + auto const result = database_.internal_db().get_header(height); + if ( ! result) { + return std::unexpected(result.error()); + } + out_work += domain::chain::header::proof(result->bits()); } - auto const height = block_result.second; - auto const result = std::make_shared(block_result.first.header()); - auto const tx_hashes = std::make_shared(block_result.first.to_hashes()); - //TODO(fernando): encapsulate header and tx_list - handler(error::success, result, height, tx_hashes, block_result.first.serialized_size()); + return out_work; } +std::expected block_chain::get_output( + domain::chain::output_point const& outpoint, + size_t branch_height, bool /*require_confirmed*/) const { -// void block_chain::fetch_merkle_block(size_t height, transaction_hashes_fetch_handler handler) const -void block_chain::fetch_merkle_block(size_t height, merkle_block_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0); - return; - } - - auto const block_result = database_.internal_db().get_block(height); - - if ( ! block_result.is_valid()) { - handler(error::not_found, nullptr, 0); - return; + auto const tx = database_.internal_db().get_transaction(outpoint.hash(), branch_height); + if ( ! tx) { + return std::unexpected(tx.error()); } - auto const merkle = std::make_shared(block_result.header(), - block_result.transactions().size(), block_result.to_hashes(), data_chunk{}); - handler(error::success, merkle, height); + return output_info{ + tx->transaction().outputs()[outpoint.index()], + tx->height(), + tx->median_time_past(), + tx->position() == 0 + }; } -void block_chain::fetch_merkle_block(hash_digest const& hash, - merkle_block_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0); - return; - } - - auto const block_result = database_.internal_db().get_block(hash); +std::expected block_chain::get_utxo( + domain::chain::output_point const& outpoint, size_t branch_height) const { - if ( ! block_result.first.is_valid()) { - handler(error::not_found, nullptr, 0); - return; + auto entry = database_.internal_db().get_utxo(outpoint); + if ( ! entry) { + return std::unexpected(entry.error()); + } + if (entry->height() > branch_height) { + return std::unexpected(database::result_code::key_not_found); } - auto const merkle = std::make_shared(block_result.first.header(), - block_result.first.transactions().size(), block_result.first.to_hashes(), data_chunk{}); - handler(error::success, merkle, block_result.second); + return output_info{ + entry->output(), + entry->height(), + entry->median_time_past(), + entry->coinbase() + }; } -void block_chain::fetch_compact_block(size_t height, compact_block_fetch_handler handler) const { - // TODO (Mario): implement compact blocks. - handler(error::not_implemented, {}, 0); +std::expected block_chain::get_utxo_pool_from(uint32_t from, uint32_t to) const { + return database_.internal_db().get_utxo_pool_from(from, to); } -void block_chain::fetch_compact_block(hash_digest const& hash, compact_block_fetch_handler handler) const { +std::expected, database::result_code> block_chain::get_transaction_position( + hash_digest const& hash, bool require_confirmed) const { + + auto const result = database_.internal_db().get_transaction(hash, max_size_t); + + if (result) { + return std::pair{result->height(), result->position()}; + } + + if (require_confirmed) { + return std::unexpected(result.error()); + } + + auto const result2 = database_.internal_db().get_transaction_unconfirmed(hash); + if ( ! result2) { + return std::unexpected(result2.error()); + } + + return std::pair{result2->height(), position_max}; +} + +// ============================================================================= +// FETCH OPERATIONS (Thread safe, coroutine-based) +// ============================================================================= + +awaitable_expected> +block_chain::fetch_block(size_t height) const { if (stopped()) { - handler(error::service_stopped, {},0); - return; + co_return std::unexpected(error::service_stopped); } - fetch_block(hash,[&handler](code const& ec, block_const_ptr message, size_t height) { - if (ec == error::success) { - auto blk_ptr = std::make_shared(compact_block::factory_from_block(*message)); - handler(error::success, blk_ptr, height); - } else { - handler(ec, nullptr, height); - } - }); + auto const cached = last_block_.load(); + if (cached && cached->validation.state && cached->validation.state->height() == height) { + co_return std::pair{cached, height}; + } + + auto const block_result = database_.internal_db().get_block(height); + if ( ! block_result) { + co_return std::unexpected(error::not_found); + } + + co_return std::pair{std::make_shared(*block_result), height}; } -// This may execute over 500 queries. -void block_chain::fetch_locator_block_hashes(get_blocks_const_ptr locator, - hash_digest const& threshold, size_t limit, - inventory_fetch_handler handler) const { +awaitable_expected> +block_chain::fetch_block(hash_digest const& hash) const { if (stopped()) { - handler(error::service_stopped, nullptr); - return; + co_return std::unexpected(error::service_stopped); } - // This is based on the idea that looking up by block hash to get heights - // will be much faster than hashing each retrieved block to test for stop. + auto const cached = last_block_.load(); + if (cached && cached->validation.state && cached->hash() == hash) { + co_return std::pair{cached, cached->validation.state->height()}; + } - // Find the start block height. - // If no start block is on our chain we start with block 0. - uint32_t start = 0; - for (auto const& hash: locator->start_hashes()) { - auto const result = database_.internal_db().get_block(hash); - if (result.first.is_valid()) - { - start = result.second; - break; - } + auto const block_result = database_.internal_db().get_block(hash); + if ( ! block_result) { + co_return std::unexpected(error::not_found); } - // The begin block requested is always one after the start block. - auto begin = *safe_add(start, uint32_t(1)); + co_return std::pair{std::make_shared(block_result->first), block_result->second}; +} - // The maximum number of headers returned is 500. - auto end = *safe_add(begin, uint32_t(limit)); +awaitable_expected> +block_chain::fetch_block_header(size_t height) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } - // Find the upper threshold block height (peer-specified). - if (locator->stop_hash() != null_hash) { - // If the stop block is not on chain we treat it as a null stop. - auto const result = database_.internal_db().get_block(locator->stop_hash()); + auto result = database_.internal_db().get_header(height); + if ( ! result) { + co_return std::unexpected(error::not_found); + } + + co_return std::pair{std::make_shared
(std::move(*result)), height}; +} - // Otherwise limit the end height to the stop block height. - // If end precedes begin floor_subtract will handle below. - if (result.first.is_valid()) - end = std::min(result.second, end); +awaitable_expected> +block_chain::fetch_block_header(hash_digest const& hash) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); } - // Find the lower threshold block height (self-specified). - if (threshold != null_hash) { - // If the threshold is not on chain we ignore it. - auto const result = database_.internal_db().get_block(threshold); + auto result = database_.internal_db().get_header(hash); + if ( ! result) { + co_return std::unexpected(error::not_found); + } + + co_return std::pair{std::make_shared
(std::move(result->first)), result->second}; +} - // Otherwise limit the begin height to the threshold block height. - // If begin exceeds end floor_subtract will handle below. - if (result.first.is_valid()) - begin = std::max(result.second, begin); +awaitable_expected +block_chain::fetch_block_height(hash_digest const& hash) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); } - auto hashes = std::make_shared(); - hashes->inventories().reserve(floor_subtract(end, begin)); + auto const result = database_.internal_db().get_header(hash); + if ( ! result) { + co_return std::unexpected(error::not_found); + } - // Build the hash list until we hit end or the blockchain top. - for (auto height = begin; height < end; ++height) { - auto const result = database_.internal_db().get_block(height); + co_return result->second; +} - // If not found then we are at our top. - if ( ! result.is_valid()) - { - hashes->inventories().shrink_to_fit(); - break; - } +awaitable_expected> +block_chain::fetch_block_hash_timestamp(size_t height) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } - static auto const id = inventory::type_id::block; - hashes->inventories().emplace_back(id, result.header().hash()); + auto const result = database_.internal_db().get_header(height); + if ( ! result) { + co_return std::unexpected(error::not_found); } - handler(error::success, std::move(hashes)); + co_return std::tuple{result->hash(), result->timestamp(), height}; } -void block_chain::fetch_ds_proof(hash_digest const& hash, ds_proof_fetch_handler handler) const { +awaitable_expected, uint64_t>> +block_chain::fetch_block_header_txs_size(hash_digest const& hash) const { if (stopped()) { - handler(error::service_stopped, nullptr); - return; + co_return std::unexpected(error::service_stopped); + } + + auto const block_result = database_.internal_db().get_block(hash); + if ( ! block_result) { + co_return std::unexpected(error::not_found); } - transaction_organizer_.fetch_ds_proof(hash, handler); + auto const height = block_result->second; + auto const hdr = std::make_shared(block_result->first.header()); + auto const tx_hashes = std::make_shared(block_result->first.to_hashes()); + + co_return std::tuple{hdr, height, tx_hashes, block_result->first.serialized_size()}; } -void block_chain::fetch_transaction(hash_digest const& hash, bool require_confirmed, transaction_fetch_handler handler) const { +awaitable_expected +block_chain::fetch_last_height() const { if (stopped()) { - handler(error::service_stopped, nullptr, 0, 0); - return; + co_return std::unexpected(error::service_stopped); + } + + auto result = database_.internal_db().get_last_heights(); + if ( ! result) { + co_return std::unexpected(error::not_found); + } + + co_return size_t(result->first); // header_height +} + +awaitable_expected> +block_chain::fetch_merkle_block(size_t height) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + + auto const block_result = database_.internal_db().get_block(height); + if ( ! block_result) { + co_return std::unexpected(error::not_found); + } + + auto merkle = std::make_shared(block_result->header(), + block_result->transactions().size(), block_result->to_hashes(), data_chunk{}); + + co_return std::pair{merkle, height}; +} + +awaitable_expected> +block_chain::fetch_merkle_block(hash_digest const& hash) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + + auto const block_result = database_.internal_db().get_block(hash); + if ( ! block_result) { + co_return std::unexpected(error::not_found); + } + auto const& [block, height] = *block_result; + + auto merkle = std::make_shared(block.header(), + block.transactions().size(), block.to_hashes(), data_chunk{}); + + co_return std::pair{merkle, height}; +} + +awaitable_expected> +block_chain::fetch_compact_block(size_t /*height*/) const { + co_return std::unexpected(error::not_implemented); +} + +awaitable_expected> +block_chain::fetch_compact_block(hash_digest const& hash) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + + auto block_result = co_await fetch_block(hash); + if ( ! block_result.has_value()) { + co_return std::unexpected(block_result.error()); + } + + auto const& [blk, height] = block_result.value(); + auto compact = std::make_shared(compact_block::factory_from_block(*blk)); + + co_return std::pair{compact, height}; +} + +awaitable_expected> +block_chain::fetch_transaction(hash_digest const& hash, bool require_confirmed) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); } + auto const result = database_.internal_db().get_transaction(hash, max_size_t); - if ( result.is_valid() ) { - auto const tx = std::make_shared(result.transaction()); - handler(error::success, tx, result.position(), result.height()); - return; + if (result) { + co_return std::tuple{ + std::make_shared(result->transaction()), + result->position(), + result->height() + }; } if (require_confirmed) { - handler(error::not_found, nullptr, 0, 0); - return; + co_return std::unexpected(error::not_found); } auto const result2 = database_.internal_db().get_transaction_unconfirmed(hash); - if ( ! result2.is_valid() ) { - handler(error::not_found, nullptr, 0, 0); - return; + if ( ! result2) { + co_return std::unexpected(error::not_found); } - auto const tx = std::make_shared(result2.transaction()); - handler(error::success, tx, position_max, result2.height()); + co_return std::tuple{ + std::make_shared(result2->transaction()), + position_max, + result2->height() + }; } -// This is same as fetch_transaction but skips deserializing the tx payload. -void block_chain::fetch_transaction_position(hash_digest const& hash, bool require_confirmed, transaction_index_fetch_handler handler) const { +awaitable_expected> +block_chain::fetch_transaction_position(hash_digest const& hash, bool require_confirmed) const { if (stopped()) { - handler(error::service_stopped, 0, 0); - return; + co_return std::unexpected(error::service_stopped); } auto const result = database_.internal_db().get_transaction(hash, max_size_t); - - if ( result.is_valid() ) { - handler(error::success, result.position(), result.height()); - return; + if (result) { + co_return std::pair{result->position(), result->height()}; } if (require_confirmed) { - handler(error::not_found, 0, 0); - return; + co_return std::unexpected(error::not_found); } auto const result2 = database_.internal_db().get_transaction_unconfirmed(hash); - if ( ! result2.is_valid() ) { - handler(error::not_found, 0, 0); - return; + if ( ! result2) { + co_return std::unexpected(error::not_found); + } + + co_return std::pair{position_max, result2->height()}; +} + +awaitable_expected +block_chain::fetch_unconfirmed_transaction(hash_digest const& hash) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + + auto const result = database_.internal_db().get_transaction_unconfirmed(hash); + if ( ! result) { + co_return std::unexpected(error::not_found); } - handler(error::success, position_max, result2.height()); + co_return std::make_shared(result->transaction()); } +awaitable_expected +block_chain::fetch_locator_block_hashes(get_blocks_const_ptr locator, + hash_digest const& threshold, + size_t limit) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } -//TODO (Mario) : Review and move to proper location -hash_digest generate_merkle_root(std::vector transactions) { - using std::swap; + uint32_t start = 0; + for (auto const& hash : locator->start_hashes()) { + auto const result = database_.internal_db().get_block(hash); + if (result) { + start = result->second; + break; + } + } - if (transactions.empty()) return null_hash; + auto begin = *safe_add(start, uint32_t(1)); + auto end = *safe_add(begin, uint32_t(limit)); - hash_list merkle; + if (locator->stop_hash() != null_hash) { + auto const result = database_.internal_db().get_block(locator->stop_hash()); + if (result) { + end = std::min(result->second, end); + } + } - auto hasher = [&merkle](transaction const& tx) { - merkle.push_back(tx.hash()); - }; + if (threshold != null_hash) { + auto const result = database_.internal_db().get_block(threshold); + if (result) { + begin = std::max(result->second, begin); + } + } + + auto hashes = std::make_shared(); + hashes->inventories().reserve(floor_subtract(end, begin)); + + for (auto height = begin; height < end; ++height) { + auto const result = database_.internal_db().get_block(height); + if ( ! result) { + hashes->inventories().shrink_to_fit(); + break; + } + static auto const id = inventory::type_id::block; + hashes->inventories().emplace_back(id, result->header().hash()); + } + + co_return hashes; +} + +awaitable_expected +block_chain::fetch_locator_block_headers(get_headers_const_ptr locator, + hash_digest const& threshold, + size_t limit) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + + size_t start = 0; + for (auto const& hash : locator->start_hashes()) { + auto const result = database_.internal_db().get_header(hash); + if (result) { + start = result->second; + break; + } + } + + auto begin = *safe_add(start, size_t(1)); + auto end = *safe_add(begin, limit); + + if (locator->stop_hash() != null_hash) { + auto const result = database_.internal_db().get_header(locator->stop_hash()); + if (result) { + end = std::min(size_t(result->second), end); + } + } - // Hash ordering matters, don't use std::transform here. - std::for_each(transactions.begin(), transactions.end(), hasher); + if (threshold != null_hash) { + auto const result = database_.internal_db().get_header(threshold); + if (result) { + begin = std::max(size_t(result->second), begin); + } + } - hash_list update; - // Initial capacity is half of the original list (clear doesn't reset). - update.reserve((merkle.size() + 1) / 2); + auto message = std::make_shared(); + message->elements().reserve(floor_subtract(end, begin)); - while (merkle.size() > 1) { - // If number of hashes is odd, duplicate last hash in the list. - if (merkle.size() % 2 != 0) { - merkle.push_back(merkle.back()); + for (auto height = begin; height < end; ++height) { + auto const result = database_.internal_db().get_header(height); + if ( ! result) { + message->elements().shrink_to_fit(); + break; } + message->elements().push_back(*result); + } + + co_return message; +} + +awaitable_expected +block_chain::fetch_block_locator(block::indexes const& heights) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + + auto message = std::make_shared(); + auto& hashes = message->start_hashes(); + hashes.reserve(heights.size()); - for (auto it = merkle.begin(); it != merkle.end(); it += 2) { - update.push_back(bitcoin_hash(build_chunk({ it[0], it[1] }))); + for (auto const height : heights) { + auto const result = database_.internal_db().get_header(height); + if ( ! result) { + co_return std::unexpected(error::not_found); } + hashes.push_back(result->hash()); + } + + co_return message; +} + +awaitable_expected +block_chain::fetch_spend(domain::chain::output_point const& outpoint) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + +#if defined(KTH_DB_SPENDS) + auto point = database_.spends().get(outpoint); +#else + auto point = database_.internal_db().get_spend(outpoint); +#endif + + if ( ! point) { + co_return std::unexpected(error::not_found); + } + + co_return *point; +} + +awaitable_expected +block_chain::fetch_history(short_hash const& address_hash, size_t limit, size_t from_height) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + +#if defined(KTH_DB_HISTORY) + auto const result = database_.history().get(address_hash, limit, from_height); +#else + auto const result = database_.internal_db().get_history(address_hash, limit, from_height); +#endif + if ( ! result) { + co_return std::unexpected(error::not_found); + } + co_return *result; +} + +awaitable_expected> +block_chain::fetch_confirmed_transactions(short_hash const& address_hash, + size_t limit, size_t from_height) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); + } + +#if defined(KTH_DB_HISTORY) + auto const result = database_.history().get_txns(address_hash, limit, from_height); +#else + auto const result = database_.internal_db().get_history_txns(address_hash, limit, from_height); +#endif + if ( ! result) { + co_return std::unexpected(error::not_found); + } + co_return *result; +} - swap(merkle, update); - update.clear(); +awaitable_expected +block_chain::fetch_ds_proof(hash_digest const& hash) const { + if (stopped()) { + co_return std::unexpected(error::service_stopped); } + co_return co_await transaction_organizer_.fetch_ds_proof(hash); +} + +// ============================================================================= +// MEMPOOL / TRANSACTION POOL +// ============================================================================= + +awaitable_expected> +block_chain::fetch_template() const { + co_return co_await transaction_organizer_.fetch_template(); +} - // There is now only one item in the list. - return merkle.front(); +awaitable_expected +block_chain::fetch_mempool(size_t count_limit, uint64_t /*minimum_fee*/) const { + co_return co_await transaction_organizer_.fetch_mempool(count_limit); } namespace { @@ -756,81 +1080,68 @@ std::tuple get_address_versions(bool use_testnet_rules) { kth::domain::wallet::payment_address::testnet_p2kh, kth::domain::wallet::payment_address::testnet_p2sh}; } - return { kth::domain::wallet::payment_address::mainnet_p2kh, kth::domain::wallet::payment_address::mainnet_p2sh}; - } } // anonymous namespace -//TODO(fernando): refactor!!! -std::vector block_chain::get_mempool_transactions(std::vector const& payment_addresses, bool use_testnet_rules) const { -/* " \"address\" (string) The base58check encoded address\n" - " \"txid\" (string) The related txid\n" - " \"index\" (number) The related input or output index\n" - " \"satoshis\" (number) The difference of satoshis\n" - " \"timestamp\" (number) The time the transaction entered the mempool (seconds)\n" - " \"prevtxid\" (string) The previous txid (if spending)\n" - " \"prevout\" (string) The previous transaction output index (if spending)\n" -*/ +std::vector block_chain::get_mempool_transactions( + std::vector const& payment_addresses, bool use_testnet_rules) const { auto const [encoding_p2kh, encoding_p2sh] = get_address_versions(use_testnet_rules); - std::vector ret; + std::vector ret; std::unordered_set addrs; for (auto const& payment_address : payment_addresses) { kth::domain::wallet::payment_address address(payment_address); - if (address){ + if (address) { addrs.insert(address); } } auto const result = database_.internal_db().get_all_transaction_unconfirmed(); + if ( ! result) { + return ret; + } - for (auto const& tx_res : result) { + for (auto const& tx_res : *result) { auto const& tx = tx_res.transaction(); - //tx.recompute_hash(); size_t i = 0; + for (auto const& output : tx.outputs()) { - auto const tx_addresses = kth::domain::wallet::payment_address::extract(output.script(), encoding_p2kh, encoding_p2sh); - for(auto const tx_address : tx_addresses) { + auto const tx_addresses = kth::domain::wallet::payment_address::extract( + output.script(), encoding_p2kh, encoding_p2sh); + for (auto const tx_address : tx_addresses) { if (tx_address && addrs.find(tx_address) != addrs.end()) { - ret.push_back - (kth::blockchain::mempool_transaction_summary - (tx_address.encoded_cashaddr(false), kth::encode_hash(tx.hash()), "", - "", std::to_string(output.value()), i, tx_res.arrival_time())); + ret.push_back(mempool_transaction_summary( + tx_address.encoded_cashaddr(false), kth::encode_hash(tx.hash()), "", + "", std::to_string(output.value()), i, tx_res.arrival_time())); } } ++i; } + i = 0; for (auto const& input : tx.inputs()) { - // TODO(kth): payment_addrress::extract should use the prev_output script instead of the input script - // see https://github.com/k-nuth/core/blob/v0.10.0/src/wallet/payment_address.cpp#L505 - auto const tx_addresses = kth::domain::wallet::payment_address::extract(input.script(), encoding_p2kh, encoding_p2sh); - for(auto const tx_address : tx_addresses) - if (tx_address && addrs.find(tx_address) != addrs.end()) { - std::latch latch(1); - fetch_transaction(input.previous_output().hash(), false, - [&](const kth::code &ec, - kth::transaction_const_ptr tx_ptr, size_t index, - size_t height) { - if (ec == kth::error::success) { - ret.push_back(kth::blockchain::mempool_transaction_summary - (tx_address.encoded_cashaddr(false), - kth::encode_hash(tx.hash()), - kth::encode_hash(input.previous_output().hash()), - std::to_string(input.previous_output().index()), - "-"+std::to_string(tx_ptr->outputs()[input.previous_output().index()].value()), - i, - tx_res.arrival_time())); - } - latch.count_down(); - }); - latch.wait(); + auto const tx_addresses = kth::domain::wallet::payment_address::extract( + input.script(), encoding_p2kh, encoding_p2sh); + for (auto const tx_address : tx_addresses) { + if (tx_address && addrs.find(tx_address) != addrs.end()) { + auto const prev_tx = database_.internal_db().get_transaction( + input.previous_output().hash(), max_size_t); + if (prev_tx) { + ret.push_back(mempool_transaction_summary( + tx_address.encoded_cashaddr(false), + kth::encode_hash(tx.hash()), + kth::encode_hash(input.previous_output().hash()), + std::to_string(input.previous_output().index()), + "-" + std::to_string(prev_tx->transaction().outputs()[input.previous_output().index()].value()), + i, tx_res.arrival_time())); + } + } } ++i; } @@ -839,25 +1150,35 @@ std::vector block_chain::get_mempo return ret; } -// Precondition: valid payment addresses -std::vector block_chain::get_mempool_transactions_from_wallets(std::vector const& payment_addresses, bool use_testnet_rules) const { +std::vector block_chain::get_mempool_transactions( + std::string const& payment_address, bool use_testnet_rules) const { + return get_mempool_transactions(std::vector{payment_address}, use_testnet_rules); +} + +std::vector block_chain::get_mempool_transactions_from_wallets( + std::vector const& payment_addresses, + bool use_testnet_rules) const { + auto const [encoding_p2kh, encoding_p2sh] = get_address_versions(use_testnet_rules); std::vector ret; - auto const result = database_.internal_db().get_all_transaction_unconfirmed(); + if ( ! result) { + return ret; + } - for (auto const& tx_res : result) { + for (auto const& tx_res : *result) { auto const& tx = tx_res.transaction(); - //tx.recompute_hash(); - // Only insert the transaction once. Avoid duplicating the tx if serveral wallets are used in the same tx, and if the same wallet is the input and output addr. bool inserted = false; - for (auto iter_output = tx.outputs().begin(); (iter_output != tx.outputs().end() && !inserted); ++iter_output) { + for (auto iter_output = tx.outputs().begin(); + iter_output != tx.outputs().end() && !inserted; ++iter_output) { - auto const tx_addresses = kth::domain::wallet::payment_address::extract((*iter_output).script(), encoding_p2kh, encoding_p2sh); + auto const tx_addresses = kth::domain::wallet::payment_address::extract( + iter_output->script(), encoding_p2kh, encoding_p2sh); - for (auto iter_addr = tx_addresses.begin(); (iter_addr != tx_addresses.end() && !inserted); ++iter_addr) { + for (auto iter_addr = tx_addresses.begin(); + iter_addr != tx_addresses.end() && !inserted; ++iter_addr) { if (*iter_addr) { auto it = std::find(payment_addresses.begin(), payment_addresses.end(), *iter_addr); if (it != payment_addresses.end()) { @@ -868,11 +1189,14 @@ std::vector block_chain::get_mempool_transactions_fr } } - for (auto iter_input = tx.inputs().begin(); (iter_input != tx.inputs().end() && !inserted); ++iter_input) { - // TODO(kth): payment_addrress::extract should use the prev_output script instead of the input script - // see https://github.com/k-nuth/core/blob/v0.10.0/src/wallet/payment_address.cpp#L505 - auto const tx_addresses = kth::domain::wallet::payment_address::extract((*iter_input).script(), encoding_p2kh, encoding_p2sh); - for (auto iter_addr = tx_addresses.begin(); (iter_addr != tx_addresses.end() && !inserted); ++iter_addr) { + for (auto iter_input = tx.inputs().begin(); + iter_input != tx.inputs().end() && !inserted; ++iter_input) { + + auto const tx_addresses = kth::domain::wallet::payment_address::extract( + iter_input->script(), encoding_p2kh, encoding_p2sh); + + for (auto iter_addr = tx_addresses.begin(); + iter_addr != tx_addresses.end() && !inserted; ++iter_addr) { if (*iter_addr) { auto it = std::find(payment_addresses.begin(), payment_addresses.end(), *iter_addr); if (it != payment_addresses.end()) { @@ -882,252 +1206,42 @@ std::vector block_chain::get_mempool_transactions_fr } } } - } return ret; } -void block_chain::fill_tx_list_from_mempool(domain::message::compact_block const& block, size_t& mempool_count, std::vector& txn_available, std::unordered_map const& shorttxids) const { +block_chain::mempool_mini_hash_map block_chain::get_mempool_mini_hash_map( + domain::message::compact_block const& block) const { - std::vector have_txn(txn_available.size()); - - auto header_hash = hash(block); - auto k0 = from_little_endian_unsafe(header_hash); - auto k1 = from_little_endian_unsafe(std::span{header_hash}.subspan(sizeof(uint64_t))); - - auto const result = database_.internal_db().get_all_transaction_unconfirmed(); - - for (auto const& tx_res : result) { - auto const& tx = tx_res.transaction(); - - uint64_t shortid = sip_hash_uint256(k0, k1, tx.hash()) & uint64_t(0xffffffffffff); - - auto idit = shorttxids.find(shortid); - if (idit != shorttxids.end()) { - if ( ! have_txn[idit->second]) { - txn_available[idit->second] = tx; - have_txn[idit->second] = true; - ++mempool_count; - } else { - // If we find two mempool txn that match the short id, just - // request it. This should be rare enough that the extra - // bandwidth doesn't matter, but eating a round-trip due to - // FillBlock failure would be annoying. - if (txn_available[idit->second].is_valid()) { - //txn_available[idit->second].reset(); - txn_available[idit->second] = domain::chain::transaction{}; - --mempool_count; - } - } - } - - //TODO (Mario) : break the loop - // Though ideally we'd continue scanning for the - // two-txn-match-shortid case, the performance win of an early exit - // here is too good to pass up and worth the extra risk. - /*if (mempool_count == shorttxids.size()) { - return false; - } else { - return true; - }*/ - } - -} - -safe_chain::mempool_mini_hash_map block_chain::get_mempool_mini_hash_map(domain::message::compact_block const& block) const { if (stopped()) { - return safe_chain::mempool_mini_hash_map(); + return mempool_mini_hash_map(); } auto header_hash = hash(block); - auto k0 = from_little_endian_unsafe(header_hash); auto k1 = from_little_endian_unsafe(std::span{header_hash}.subspan(sizeof(uint64_t))); - safe_chain::mempool_mini_hash_map mempool; - - + mempool_mini_hash_map mempool; auto const result = database_.internal_db().get_all_transaction_unconfirmed(); + if ( ! result) { + return mempool; + } - for (auto const& tx_res : result) { + for (auto const& tx_res : *result) { auto const& tx = tx_res.transaction(); - auto sh = sip_hash_uint256(k0, k1, tx.hash()); - - /* to_little_endian() - uint64_t pepe = 4564564; - uint64_t pepe2 = pepe & 0x0000ffffffffffff; - - reinterpret_cast(pepe2); - */ - //Drop the most significative bytes from the sh mini_hash short_id; - mempool.emplace(short_id,tx); - + mempool.emplace(short_id, tx); } return mempool; } -std::vector block_chain::get_mempool_transactions(std::string const& payment_address, bool use_testnet_rules) const{ - std::vector addresses = {payment_address}; - return get_mempool_transactions(addresses, use_testnet_rules); -} - - -void block_chain::fetch_unconfirmed_transaction(hash_digest const& hash, transaction_unconfirmed_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr); - return; - } - - auto const result = database_.internal_db().get_transaction_unconfirmed(hash); - - if ( ! result.is_valid()) { - handler(error::not_found, nullptr); - return; - } - - auto const tx = std::make_shared(result.transaction()); - handler(error::success, tx); -} - - - -#ifdef KTH_DB_TRANSACTION_UNCONFIRMED -//TODO(fernando): refactor!!! -std::vector block_chain::get_mempool_transactions(std::vector const& payment_addresses, bool use_testnet_rules) const { -/* " \"address\" (string) The base58check encoded address\n" - " \"txid\" (string) The related txid\n" - " \"index\" (number) The related input or output index\n" - " \"satoshis\" (number) The difference of satoshis\n" - " \"timestamp\" (number) The time the transaction entered the mempool (seconds)\n" - " \"prevtxid\" (string) The previous txid (if spending)\n" - " \"prevout\" (string) The previous transaction output index (if spending)\n" -*/ - - auto const [encoding_p2kh, encoding_p2sh] = get_address_versions(use_testnet_rules); - - std::vector ret; - std::unordered_set addrs; - for (auto const& payment_address : payment_addresses) { - kth::domain::wallet::payment_address address(payment_address); - if (address){ - addrs.insert(address); - } - } - - database_.transactions_unconfirmed().for_each_result([&](kth::database::transaction_unconfirmed_result const& tx_res) { - auto tx = tx_res.transaction(); - tx.recompute_hash(); - size_t i = 0; - for (auto const& output : tx.outputs()) { - auto const tx_addresses = kth::domain::wallet::payment_address::extract(output.script(), encoding_p2kh, encoding_p2sh); - for(auto const tx_address : tx_addresses) { - if (tx_address && addrs.find(tx_address) != addrs.end()) { - ret.push_back - (kth::blockchain::mempool_transaction_summary - (tx_address.encoded_cashaddr(false), kth::encode_hash(tx.hash()), "", - "", std::to_string(output.value()), i, tx_res.arrival_time())); - } - } - ++i; - } - i = 0; - for (auto const& input : tx.inputs()) { - // TODO(kth): payment_addrress::extract should use the prev_output script instead of the input script - // see https://github.com/k-nuth/core/blob/v0.10.0/src/wallet/payment_address.cpp#L505 - auto const tx_addresses = kth::domain::wallet::payment_address::extract(input.script(), encoding_p2kh, encoding_p2sh); - for(auto const tx_address : tx_addresses) - if (tx_address && addrs.find(tx_address) != addrs.end()) { - std::latch latch(1); - fetch_transaction(input.previous_output().hash(), false, - [&](const kth::code &ec, - kth::transaction_const_ptr tx_ptr, size_t index, - size_t height) { - if (ec == kth::error::success) { - ret.push_back(kth::blockchain::mempool_transaction_summary - (tx_address.encoded_cashaddr(false), - kth::encode_hash(tx.hash()), - kth::encode_hash(input.previous_output().hash()), - std::to_string(input.previous_output().index()), - "-"+std::to_string(tx_ptr->outputs()[input.previous_output().index()].value()), - i, - tx_res.arrival_time())); - } - latch.count_down(); - }); - latch.wait(); - } - ++i; - } - return true; - }); - - return ret; -} - -// Precondition: valid payment addresses -std::vector block_chain::get_mempool_transactions_from_wallets(std::vector const& payment_addresses, bool use_testnet_rules) const { - auto const [encoding_p2kh, encoding_p2sh] = get_address_versions(use_testnet_rules); - - std::vector ret; - - database_.transactions_unconfirmed().for_each_result([&](kth::database::transaction_unconfirmed_result const& tx_res) { - auto tx = tx_res.transaction(); - tx.recompute_hash(); - - // Only insert the transaction once. Avoid duplicating the tx if serveral wallets are used in the same tx, and if the same wallet is the input and output addr. - bool inserted = false; - - for (auto iter_output = tx.outputs().begin(); (iter_output != tx.outputs().end() && !inserted); ++iter_output) { - - auto const tx_addresses = kth::domain::wallet::payment_address::extract((*iter_output).script(), encoding_p2kh, encoding_p2sh); - - for (auto iter_addr = tx_addresses.begin(); (iter_addr != tx_addresses.end() && !inserted); ++iter_addr) { - if (*iter_addr) { - auto it = std::find(payment_addresses.begin(), payment_addresses.end(), *iter_addr); - if (it != payment_addresses.end()) { - ret.push_back(tx); - inserted = true; - } - } - } - } - - for (auto iter_input = tx.inputs().begin(); (iter_input != tx.inputs().end() && !inserted); ++iter_input) { - // TODO(kth): payment_addrress::extract should use the prev_output script instead of the input script - // see https://github.com/k-nuth/core/blob/v0.10.0/src/wallet/payment_address.cpp#L505 - auto const tx_addresses = kth::domain::wallet::payment_address::extract((*iter_input).script(), encoding_p2kh, encoding_p2sh); - for (auto iter_addr = tx_addresses.begin(); (iter_addr != tx_addresses.end() && !inserted); ++iter_addr) { - if (*iter_addr) { - auto it = std::find(payment_addresses.begin(), payment_addresses.end(), *iter_addr); - if (it != payment_addresses.end()) { - ret.push_back(tx); - inserted = true; - } - } - } - } - return true; - }); - - return ret; -} - -/* - def get_siphash_keys(self): - header_nonce = self.header.serialize() - header_nonce += struct.pack("& txn_available, std::unordered_map const& shorttxids) const { +void block_chain::fill_tx_list_from_mempool(domain::message::compact_block const& block, + size_t& mempool_count, + std::vector& txn_available, + std::unordered_map const& shorttxids) const { std::vector have_txn(txn_available.size()); @@ -1135,12 +1249,16 @@ void block_chain::fill_tx_list_from_mempool(domain::message::compact_block const auto k0 = from_little_endian_unsafe(header_hash); auto k1 = from_little_endian_unsafe(std::span{header_hash}.subspan(sizeof(uint64_t))); + auto const result = database_.internal_db().get_all_transaction_unconfirmed(); + if ( ! result) { + return; + } - // spdlog::info("[blockchain] fill_tx_list_from_mempool header_hash -> {} k0 {} k1 {}", encode_hash(header_hash), k0, k1); + for (auto const& tx_res : *result) { + auto const& tx = tx_res.transaction(); - database_.transactions_unconfirmed().for_each([&](domain::chain::transaction const& tx) { uint64_t shortid = sip_hash_uint256(k0, k1, tx.hash()) & uint64_t(0xffffffffffff); - // spdlog::info("[blockchain] mempool tx -> {} shortid {}", encode_hash(tx.hash()), shortid); + auto idit = shorttxids.find(shortid); if (idit != shorttxids.end()) { if ( ! have_txn[idit->second]) { @@ -1148,370 +1266,52 @@ void block_chain::fill_tx_list_from_mempool(domain::message::compact_block const have_txn[idit->second] = true; ++mempool_count; } else { - // If we find two mempool txn that match the short id, just - // request it. This should be rare enough that the extra - // bandwidth doesn't matter, but eating a round-trip due to - // FillBlock failure would be annoying. if (txn_available[idit->second].is_valid()) { - //txn_available[idit->second].reset(); txn_available[idit->second] = domain::chain::transaction{}; --mempool_count; } } } - // Though ideally we'd continue scanning for the - // two-txn-match-shortid case, the performance win of an early exit - // here is too good to pass up and worth the extra risk. - if (mempool_count == shorttxids.size()) { - return false; - } else { - return true; - } - }); -} - -safe_chain::mempool_mini_hash_map block_chain::get_mempool_mini_hash_map(domain::message::compact_block const& block) const { - if (stopped()) { - return safe_chain::mempool_mini_hash_map(); - } - - auto header_hash = hash(block); - - auto k0 = from_little_endian_unsafe(header_hash); - auto k1 = from_little_endian_unsafe(std::span{header_hash}.subspan(sizeof(uint64_t))); - - safe_chain::mempool_mini_hash_map mempool; - - database_.transactions_unconfirmed().for_each([&](domain::chain::transaction const& tx) { - - auto sh = sip_hash_uint256(k0, k1, tx.hash()); - - /* to_little_endian() - uint64_t pepe = 4564564; - uint64_t pepe2 = pepe & 0x0000ffffffffffff; - - reinterpret_cast(pepe2); - */ - //Drop the most significative bytes from the sh - mini_hash short_id; - mempool.emplace(short_id,tx); - return true; - }); - - return mempool; -} - -std::vector block_chain::get_mempool_transactions(std::string const& payment_address, bool use_testnet_rules) const{ - std::vector addresses = {payment_address}; - return get_mempool_transactions(addresses, use_testnet_rules); -} - - - -void block_chain::fetch_unconfirmed_transaction(hash_digest const& hash, transaction_unconfirmed_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr); - return; - } - - auto const result = database_.transactions_unconfirmed().get(hash); - - if ( ! result) { - handler(error::not_found, nullptr); - return; - } - - auto const tx = std::make_shared(result.transaction()); - handler(error::success, tx); -} - - -#endif // KTH_DB_TRANSACTION_UNCONFIRMED - -void block_chain::fetch_block_hash_timestamp(size_t height, block_hash_time_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, null_hash, 0, 0); - return; - } - - auto const result = database_.internal_db().get_header(height); - - if ( ! result.is_valid() ) { - handler(error::not_found, null_hash, 0, 0); - return; - } - - handler(error::success, result.hash(), result.timestamp(), height); - -} - - -void block_chain::fetch_block_height(hash_digest const& hash, - block_height_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, {}); - return; - } - - auto const result = database_.internal_db().get_header(hash); - - if ( ! result.first.is_valid() ) { - handler(error::not_found, 0); - return; - } - - handler(error::success, result.second); -} - - -void block_chain::fetch_block_header(size_t height, - block_header_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0); - return; - } - - auto const result = database_.internal_db().get_header(height); - - if ( ! result.is_valid()) { - handler(error::not_found, nullptr, 0); - return; - } - - auto const message = std::make_shared
(std::move(result)); - handler(error::success, message, height); -} - -void block_chain::fetch_block_header(hash_digest const& hash, - block_header_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr, 0); - return; - } - - auto const result = database_.internal_db().get_header(hash); - - if ( ! result.first.is_valid() ) { - handler(error::not_found, nullptr, 0); - return; - } - - auto const message = std::make_shared
(std::move(result.first)); - handler(error::success, message, result.second); -} - - -void block_chain::fetch_last_height(last_height_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, {}); - return; - } - - uint32_t last_height; - - if ( database_.internal_db().get_last_height(last_height) != database::result_code::success ) { - handler(error::not_found, 0); - return; - } - - handler(error::success, last_height); -} - -// This may execute over 2000 queries. -void block_chain::fetch_locator_block_headers(get_headers_const_ptr locator, hash_digest const& threshold, size_t limit, locator_block_headers_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, nullptr); - return; - } - - // This is based on the idea that looking up by block hash to get heights - // will be much faster than hashing each retrieved block to test for stop. - - // Find the start block height. - // If no start block is on our chain we start with block 0. - size_t start = 0; - for (auto const& hash: locator->start_hashes()) { - auto const result = database_.internal_db().get_header(hash); - if (result.first.is_valid()) { - start = result.second; //result.height(); - break; - } - } - - // The begin block requested is always one after the start block. - auto begin = *safe_add(start, size_t(1)); - - // The maximum number of headers returned is 2000. - auto end = *safe_add(begin, limit); - - // Find the upper threshold block height (peer-specified). - if (locator->stop_hash() != null_hash) { - // If the stop block is not on chain we treat it as a null stop. - auto const result = database_.internal_db().get_header(locator->stop_hash()); - - // Otherwise limit the end height to the stop block height. - // If end precedes begin floor_subtract will handle below. - if (result.first.is_valid()) { - // end = std::min(result.height(), end); - end = std::min(size_t(result.second), end); - } - } - - // Find the lower threshold block height (self-specified). - if (threshold != null_hash) { - // If the threshold is not on chain we ignore it. - auto const result = database_.internal_db().get_header(threshold); - - // Otherwise limit the begin height to the threshold block height. - // If begin exceeds end floor_subtract will handle below. - if (result.first.is_valid()) { - // begin = std::max(result.height(), begin); - begin = std::max(size_t(result.second), begin); - } - } - - auto message = std::make_shared(); - message->elements().reserve(floor_subtract(end, begin)); - - // Build the hash list until we hit end or the blockchain top. - for (auto height = begin; height < end; ++height) { - auto const result = database_.internal_db().get_header(height); - - // If not found then we are at our top. - if ( ! result.is_valid()) { - message->elements().shrink_to_fit(); - break; - } - message->elements().push_back(result); } - handler(error::success, std::move(message)); } -// This may generally execute 29+ queries. -void block_chain::fetch_block_locator(block::indexes const& heights, block_locator_fetch_handler handler) const { +// ============================================================================= +// FILTERS +// ============================================================================= +::asio::awaitable block_chain::filter_blocks(get_data_ptr message) const { if (stopped()) { - handler(error::service_stopped, nullptr); - return; + co_return error::service_stopped; } - // Caller can cast get_headers down to get_blocks. - auto message = std::make_shared(); - auto& hashes = message->start_hashes(); - hashes.reserve(heights.size()); + block_organizer_.filter(message); + auto& inventories = message->inventories(); + auto const& internal_db = database_.internal_db(); - for (auto const height : heights) { - auto const result = database_.internal_db().get_header(height); - if ( ! result.is_valid()) { - handler(error::not_found, nullptr); - break; + for (auto it = inventories.begin(); it != inventories.end();) { + auto const header = internal_db.get_header(it->hash()); + if (it->is_block_type() && header && header->first.is_valid()) { + it = inventories.erase(it); + } else { + ++it; } - hashes.push_back(result.hash()); - } - - handler(error::success, message); -} - -// Server Queries. -//----------------------------------------------------------------------------- -void block_chain::fetch_spend(const domain::chain::output_point& outpoint, spend_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, {}); - return; - } - - #if defined(KTH_DB_SPENDS) - auto point = database_.spends().get(outpoint); - #else - auto point = database_.internal_db().get_spend(outpoint); - #endif - - if (point.hash() == null_hash) { - handler(error::not_found, {}); - return; } - handler(error::success, std::move(point)); + co_return error::success; } -void block_chain::fetch_history(short_hash const& address_hash, size_t limit, size_t from_height, history_fetch_handler handler) const { +::asio::awaitable block_chain::filter_transactions(get_data_ptr message) const { if (stopped()) { - handler(error::service_stopped, {}); - return; - } - -#if defined(KTH_DB_HISTORY) - handler(error::success, database_.history().get(address_hash, limit, from_height)); -#else - handler(error::success, database_.internal_db().get_history(address_hash, limit, from_height)); -#endif - -} - -void block_chain::fetch_confirmed_transactions(short_hash const& address_hash, size_t limit, size_t from_height, confirmed_transactions_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, {}); - return; - } - -#if defined(KTH_DB_HISTORY) - handler(error::success, database_.history().get_txns(address_hash, limit, from_height)); -#else - handler(error::success, database_.internal_db().get_history_txns(address_hash, limit, from_height)); -#endif -} - - -#ifdef KTH_DB_STEALTH -void block_chain::fetch_stealth(binary const& filter, size_t from_height, stealth_fetch_handler handler) const { - if (stopped()) { - handler(error::service_stopped, {}); - return; - } - - handler(error::success, database_.stealth().scan(filter, from_height)); -} -#endif // KTH_DB_STEALTH - -// Transaction Pool. -//----------------------------------------------------------------------------- - -// Same as fetch_mempool but also optimized for maximum possible block fee as -// limited by total bytes and signature operations. -void block_chain::fetch_template(merkle_block_fetch_handler handler) const { - transaction_organizer_.fetch_template(handler); -} - -// Fetch a set of currently-valid unconfirmed txs in dependency order. -// All txs satisfy the fee minimum and are valid at the next chain state. -// The set of blocks is limited in count to size. The set may have internal -// dependencies but all inputs must be satisfied at the current height. -void block_chain::fetch_mempool(size_t count_limit, uint64_t minimum_fee, - inventory_fetch_handler handler) const { - transaction_organizer_.fetch_mempool(count_limit, handler); -} - -// Filters. -//----------------------------------------------------------------------------- - -// This filters against all transactions (confirmed and unconfirmed). -void block_chain::filter_transactions(get_data_ptr message, result_handler handler) const { - // This filters against all transactions (confirmed and unconfirmed). - - if (stopped()) { - handler(error::service_stopped); - return; + co_return error::service_stopped; } auto& inventories = message->inventories(); -//TODO(fernando): Do we have to use the mempool when both KTH_DB_NEW_FULL and KTH_WITH_MEMPOOL are activated? #if defined(KTH_WITH_MEMPOOL) auto validated_txs = mempool_.get_validated_txs_low(); if (validated_txs.empty()) { - handler(error::success); - return; + co_return error::success; } for (auto it = inventories.begin(); it != inventories.end();) { @@ -1523,146 +1323,17 @@ void block_chain::filter_transactions(get_data_ptr message, result_handler handl } } #else - - size_t out_height; - size_t out_position; - for (auto it = inventories.begin(); it != inventories.end();) { - //Knuth: We don't store spent information - if (it->is_transaction_type() - //&& get_is_unspent_transaction(it->hash(), max_size_t, false)) - && get_transaction_position(out_height, out_position, it->hash(), false)) { + auto const pos = get_transaction_position(it->hash(), false); + if (it->is_transaction_type() && pos) { it = inventories.erase(it); } else { ++it; } } - #endif - handler(error::success); -} - -// This may execute up to 500 queries. -// This filters against the block pool and then the block chain. -void block_chain::filter_blocks(get_data_ptr message, result_handler handler) const { - - if (stopped()) { - handler(error::service_stopped); - return; - } - - // Filter through block pool first. - block_organizer_.filter(message); - auto& inventories = message->inventories(); - auto const& internal_db = database_.internal_db(); - - for (auto it = inventories.begin(); it != inventories.end();) { - if (it->is_block_type() && internal_db.get_header(it->hash()).first.is_valid()) { - it = inventories.erase(it); - } else { - ++it; - } - } - - handler(error::success); -} - -// Subscribers. -//----------------------------------------------------------------------------- - -void block_chain::subscribe_blockchain(reorganize_handler&& handler) { - // Pass this through to the organizer, which issues the notifications. - block_organizer_.subscribe(std::move(handler)); -} - -void block_chain::subscribe_transaction(transaction_handler&& handler) { - // Pass this through to the tx organizer, which issues the notifications. - transaction_organizer_.subscribe(std::move(handler)); + co_return error::success; } -void block_chain::subscribe_ds_proof(ds_proof_handler&& handler) { - // Pass this through to the tx organizer, which issues the notifications. - transaction_organizer_.subscribe_ds_proof(std::move(handler)); -} - -void block_chain::unsubscribe() { - block_organizer_.unsubscribe(); - transaction_organizer_.unsubscribe(); - transaction_organizer_.unsubscribe_ds_proof(); -} - -// Transaction Validation. -//----------------------------------------------------------------------------- - -void block_chain::transaction_validate(transaction_const_ptr tx, result_handler handler) const { - transaction_organizer_.transaction_validate(tx, handler); -} - -// Organizers. -//----------------------------------------------------------------------------- - -void block_chain::organize(block_const_ptr block, result_handler handler) { - // This cannot call organize or stop (lock safe). - block_organizer_.organize(block, handler); -} - -void block_chain::organize(transaction_const_ptr tx, result_handler handler) { - // This cannot call organize or stop (lock safe). - transaction_organizer_.organize(tx, handler); -} - -void block_chain::organize(double_spend_proof_const_ptr ds_proof, result_handler handler) { - // This cannot call organize or stop (lock safe). - transaction_organizer_.organize(ds_proof, handler); -} - - -// Properties (thread safe). -// ---------------------------------------------------------------------------- - -inline -bool block_chain::is_stale_fast() const { - return is_stale(); -} - -bool block_chain::is_stale() const { - // If there is no limit set the chain is never considered stale. - if (notify_limit_seconds_ == 0) { - return false; - } - - auto const top = last_block_.load(); - - // TODO(fernando): refactor this! - // Knuth: get the last block if there is no cache - uint32_t last_timestamp = 0; - if ( ! top) { - size_t last_height; - if (get_last_height(last_height)) { - domain::chain::header last_header; - if (get_header(last_header, last_height)) { - last_timestamp = last_header.timestamp(); - } - } - } - auto const timestamp = top ? top->header().timestamp() : last_timestamp; - return timestamp < floor_subtract(zulu_time(), notify_limit_seconds_); -} - -settings const& block_chain::chain_settings() const { - return settings_; -} - -// protected -bool block_chain::stopped() const { - return stopped_; -} - -#if defined(KTH_WITH_MEMPOOL) -std::pair, uint64_t> block_chain::get_block_template() const { - return mempool_.get_block_template(); -} -#endif - -}} // namespace kth::blockchain \ No newline at end of file +}} // namespace kth::blockchain diff --git a/src/blockchain/src/pools/block_organizer.cpp b/src/blockchain/src/pools/block_organizer.cpp index 6cc4831f..cd418fcf 100644 --- a/src/blockchain/src/pools/block_organizer.cpp +++ b/src/blockchain/src/pools/block_organizer.cpp @@ -6,22 +6,24 @@ #include #include -#include #include #include -#include +#include #include #include #include #include #include +#include +#include +#include + namespace kth::blockchain { using namespace kd::chain; using namespace kd::config; -using namespace std::placeholders; #define NAME "block_organizer" @@ -32,21 +34,22 @@ using namespace std::placeholders; // transaction: { exists, height, output } #if defined(KTH_WITH_MEMPOOL) -block_organizer::block_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool& mp) +block_organizer::block_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool& mp) #else -block_organizer::block_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions) +block_organizer::block_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings, domain::config::network network, bool relay_transactions) #endif - : fast_chain_(chain) + : chain_(chain) , mutex_(mutex) , stopped_(true) - , dispatch_(dispatch) + , executor_(std::move(executor)) + , threads_(threads) , block_pool_(settings.reorganization_limit) #if defined(KTH_WITH_MEMPOOL) - , validator_(dispatch, fast_chain_, settings, network, relay_transactions, mp) + , validator_(executor_, threads_, chain_, settings, network, relay_transactions, mp) #else - , validator_(dispatch, fast_chain_, settings, network, relay_transactions) + , validator_(executor_, threads_, chain_, settings, network, relay_transactions) #endif - , subscriber_(std::make_shared(thread_pool, NAME)) + , broadcaster_(executor_) #if defined(KTH_WITH_MEMPOOL) , mempool_(mp) @@ -65,15 +68,14 @@ bool block_organizer::stopped() const { bool block_organizer::start() { stopped_ = false; - subscriber_->start(); + broadcaster_.start(); validator_.start(); return true; } bool block_organizer::stop() { validator_.stop(); - subscriber_->stop(); - subscriber_->invoke(error::service_stopped, 0, {}, {}); + broadcaster_.stop(); stopped_ = true; return true; } @@ -81,60 +83,34 @@ bool block_organizer::stop() { // Organize sequence. //----------------------------------------------------------------------------- -// This is called from blockchain::organize. -void block_organizer::organize(block_const_ptr block, result_handler handler) { +::asio::awaitable block_organizer::organize(block_const_ptr block) { // Critical Section /////////////////////////////////////////////////////////////////////////// - mutex_.lock_high_priority(); + mutex_.lock_high_priority(); //TODO: is it possible to remove this mutex? + //TODO: any smart way to avoid blocking other high priority tasks during await? if (stopped()) { mutex_.unlock_high_priority(); - handler(error::service_stopped); - return; + co_return error::service_stopped; } - // Reset the reusable promise. - resume_ = std::promise(); - - result_handler const complete = std::bind(&block_organizer::signal_completion, this, _1); - auto const check_handler = std::bind(&block_organizer::handle_check, this, _1, block, complete); + // The block hasn't been checked yet. + if (block->transactions().empty()) { + mutex_.unlock_high_priority(); + co_return error::success; + } // Checks that are independent of chain state. - validator_.check(block, check_handler); - - // Wait on completion signal. - // This is necessary in order to continue on a non-priority thread. - // If we do not wait on the original thread there may be none left. - auto ec = resume_.get_future().get(); - - mutex_.unlock_high_priority(); - /////////////////////////////////////////////////////////////////////////// - - // Invoke caller handler outside of critical section. - handler(ec); -} - -// private -void block_organizer::signal_completion(code const& ec) { - // This must be protected so that it is properly cleared. - // Signal completion, which results in original handler invoke with code. - resume_.set_value(ec); -} - -// Verify sub-sequence. -//----------------------------------------------------------------------------- - -// private -void block_organizer::handle_check(code const& ec, block_const_ptr block, result_handler handler) { + auto ec = co_await validator_.check(block); if (stopped()) { - handler(error::service_stopped); - return; + mutex_.unlock_high_priority(); + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + mutex_.unlock_high_priority(); + co_return ec; } // Verify the last branch block (all others are verified). @@ -147,39 +123,115 @@ void block_organizer::handle_check(code const& ec, block_const_ptr block, result // it is not applied at the branch point, so some nodes will not see the // collision block and others will, depending on block order of arrival. //************************************************************************* - if (branch->empty() || fast_chain_.get_block_exists(block->hash())) { - handler(error::duplicate_block); - return; + if (branch->empty() || chain_.block_exists(block->hash())) { + mutex_.unlock_high_priority(); + co_return error::duplicate_block; } if ( ! set_branch_height(branch)) { - handler(error::orphan_block); - return; + mutex_.unlock_high_priority(); + co_return error::orphan_block; } + // Checks that are dependent on chain state and prevouts. + ec = co_await validator_.accept(branch); - auto const accept_handler = std::bind(&block_organizer::handle_accept, this, _1, branch, handler); + if (stopped()) { + mutex_.unlock_high_priority(); + co_return error::service_stopped; + } - // Checks that are dependent on chain state and prevouts. - validator_.accept(branch, accept_handler); -} + if (ec) { + mutex_.unlock_high_priority(); + co_return ec; + } + + // Checks that include script validation. + ec = co_await validator_.connect(branch); -// private -void block_organizer::handle_accept(code const& ec, branch::ptr branch, result_handler handler) { if (stopped()) { - handler(error::service_stopped); - return; + mutex_.unlock_high_priority(); + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + mutex_.unlock_high_priority(); + co_return ec; } - auto const connect_handler = std::bind(&block_organizer::handle_connect, this, _1, branch, handler); + auto& top_block = branch->top()->validation; + top_block.error = error::success; - // Checks that include script validation. - validator_.connect(branch, connect_handler); + auto& top_header = branch->top()->header().validation; + top_header.median_time_past = top_block.state->median_time_past(); + top_header.height = branch->top_height(); + + auto const work = branch->work(); + auto const first_height = branch->height() + 1u; + top_block.start_notify = asio::steady_clock::now(); + + // The chain query will stop if it reaches work level. + auto const threshold = chain_.get_branch_work(work, first_height); + if ( ! threshold) { + mutex_.unlock_high_priority(); + co_return error::branch_work_failed; + } + + // TODO(legacy): consider relay of pooled blocks by modifying subscriber semantics. + if (work <= *threshold) { + if ( ! top_block.simulate) { + block_pool_.add(branch->top()); + } + + mutex_.unlock_high_priority(); + co_return error::insufficient_work; + } + + //Note(fernando): If there is just one block, internal double spend was checked previously. + if (branch->blocks() && branch->blocks()->size() > 1) { + if (is_branch_double_spend(branch)) { + mutex_.unlock_high_priority(); + co_return error::double_spend; + } + } + + // TODO(legacy): create a simulated validation path that does not block others. + if (top_block.simulate) { + mutex_.unlock_high_priority(); + co_return error::success; + } + +#if ! defined(KTH_DB_READONLY) + // Replace! Switch! + //######################################################################### + // Incoming blocks must have median_time_past set. + auto reorg_result = co_await chain_.reorganize(branch->fork_point(), branch->blocks()); + + if ( ! reorg_result.has_value()) { + spdlog::critical("[blockchain] Failure writing block to store, is now corrupted: {}", reorg_result.error().message()); + mutex_.unlock_high_priority(); + co_return reorg_result.error(); + } + + auto out_blocks = std::move(reorg_result.value()); + + block_pool_.remove(branch->blocks()); + block_pool_.prune(branch->top_height()); + block_pool_.add(out_blocks); + +#if defined(KTH_WITH_MEMPOOL) + organize_mempool(branch, branch->blocks(), out_blocks); +#endif + + // v3 reorg block order is reverse of v2, branch.back() is the new top. + notify(branch->height(), branch->blocks(), out_blocks); + + chain_.prune_reorg_async(); + //######################################################################### +#endif // ! defined(KTH_DB_READONLY) + + mutex_.unlock_high_priority(); + co_return ec; } bool block_organizer::is_branch_double_spend(branch::ptr const& branch) const { @@ -230,10 +282,15 @@ void block_organizer::populate_prevout_1(branch::const_ptr branch, domain::chain } //TODO(fernando): check the value of the parameters: branch_height and require_confirmed - if ( ! fast_chain_.get_utxo(prevout.cache, prevout.height, prevout.median_time_past, prevout.coinbase, outpoint, branch_height)) { + auto const utxo = chain_.get_utxo(outpoint, branch_height); + if ( ! utxo) { // std::println("{}", "outpoint not found in UTXO: " << encode_hash(outpoint.hash()) << " - " << outpoint.index()); return; } + prevout.cache = utxo->output; + prevout.height = utxo->height; + prevout.median_time_past = utxo->median_time_past; + prevout.coinbase = utxo->coinbase; // BUGBUG: Spends are not marked as spent by unconfirmed transactions. // So tx pool transactions currently have no double spend limitation. @@ -311,7 +368,7 @@ void block_organizer::organize_mempool(branch::const_ptr branch, block_const_ptr mempool_.remove(block->transactions().begin() + 1, block->transactions().end(), block->non_coinbase_input_count()); - if ( ! fast_chain_.is_stale_fast() && ! outgoing_blocks->empty()) { + if ( ! chain_.is_stale() && ! outgoing_blocks->empty()) { std::for_each(block->transactions().begin() + 1, block->transactions().end(), [&txs_in, &prevouts_in](domain::chain::transaction const& tx){ txs_in.insert(tx.hash()); @@ -323,7 +380,7 @@ void block_organizer::organize_mempool(branch::const_ptr branch, block_const_ptr } } - if ( ! fast_chain_.is_stale_fast() && ! outgoing_blocks->empty()) { + if ( ! chain_.is_stale() && ! outgoing_blocks->empty()) { auto branch_utxo = create_outgoing_utxo_set(outgoing_blocks); for (auto const& block : *outgoing_blocks) { @@ -342,7 +399,7 @@ void block_organizer::organize_mempool(branch::const_ptr branch, block_const_ptr }); if ( ! double_spend) { - tx.validation.state = fast_chain_.chain_state(); + tx.validation.state = chain_.chain_state(); populate_transaction_inputs(branch, tx.inputs(), branch_utxo); mempool_.add(tx); //TODO(fernando): add bulk } @@ -354,119 +411,19 @@ void block_organizer::organize_mempool(branch::const_ptr branch, block_const_ptr } #endif // defined(KTH_WITH_MEMPOOL) -// private -void block_organizer::handle_connect(code const& ec, branch::ptr branch, result_handler handler) { - - if (stopped()) { - handler(error::service_stopped); - return; - } - - if (ec) { - handler(ec); - return; - } - - auto& top_block = branch->top()->validation; - top_block.error = error::success; - - auto& top_header = branch->top()->header().validation; - top_header.median_time_past = top_block.state->median_time_past(); - top_header.height = branch->top_height(); - - uint256_t threshold; - auto const work = branch->work(); - auto const first_height = branch->height() + 1u; - top_block.start_notify = asio::steady_clock::now(); - - // The chain query will stop if it reaches work level. - if ( ! fast_chain_.get_branch_work(threshold, work, first_height)) { - handler(error::branch_work_failed); - return; - } - - // TODO(legacy): consider relay of pooled blocks by modifying subscriber semantics. - if (work <= threshold) { - if ( ! top_block.simulate) { - block_pool_.add(branch->top()); - } - - handler(error::insufficient_work); - return; - } - - //Note(fernando): If there is just one block, internal double spend was checked previously. - if (branch->blocks() && branch->blocks()->size() > 1) { - if (is_branch_double_spend(branch)) { - handler(error::double_spend); - return; - } - } - - // TODO(legacy): create a simulated validation path that does not block others. - if (top_block.simulate) { - handler(error::success); - return; - } - - -#if ! defined(KTH_DB_READONLY) - // Get the outgoing blocks to forward to reorg handler. - auto const out_blocks = std::make_shared(); - auto const reorganized_handler = std::bind(&block_organizer::handle_reorganized, this, _1, branch, out_blocks, handler); - - // Replace! Switch! - //######################################################################### - // Incoming blocks must have median_time_past set. - fast_chain_.reorganize(branch->fork_point(), branch->blocks(), out_blocks, dispatch_, reorganized_handler); - //######################################################################### -#endif // ! defined(KTH_DB_READONLY) -} - -#if ! defined(KTH_DB_READONLY) -// private -// Outgoing blocks must have median_time_past set. -void block_organizer::handle_reorganized(code const& ec, branch::const_ptr branch, block_const_ptr_list_ptr outgoing, result_handler handler) { - if (ec) { - spdlog::critical("[blockchain] Failure writing block to store, is now corrupted: {}", ec.message()); - handler(ec); - return; - } - - block_pool_.remove(branch->blocks()); - block_pool_.prune(branch->top_height()); - block_pool_.add(outgoing); - - -#if defined(KTH_WITH_MEMPOOL) - organize_mempool(branch, branch->blocks(), outgoing); -#endif - - // v3 reorg block order is reverse of v2, branch.back() is the new top. - notify(branch->height(), branch->blocks(), outgoing); - - fast_chain_.prune_reorg_async(); - //fast_chain_.set_database_flags(); - - handler(error::success); -} -#endif // ! defined(KTH_DB_READONLY) - // Subscription. //----------------------------------------------------------------------------- -// private void block_organizer::notify(size_t branch_height, block_const_ptr_list_const_ptr branch, block_const_ptr_list_const_ptr original) { - // This invokes handlers within the criticial section (deadlock risk). - subscriber_->invoke(error::success, branch_height, branch, original); + broadcaster_.publish(branch_height, branch, original); } -void block_organizer::subscribe(reorganize_handler&& handler) { - subscriber_->subscribe(std::move(handler), error::service_stopped, 0, {}, {}); +block_organizer::block_broadcaster::channel_ptr block_organizer::subscribe() { + return broadcaster_.subscribe(); } -void block_organizer::unsubscribe() { - subscriber_->relay(error::success, 0, {}, {}); +void block_organizer::unsubscribe(block_broadcaster::channel_ptr const& channel) { + broadcaster_.unsubscribe(channel); } // Queries. @@ -481,15 +438,14 @@ void block_organizer::filter(get_data_ptr message) const { // TODO(legacy): store this in the block pool and avoid this query. bool block_organizer::set_branch_height(branch::ptr branch) { - size_t height; - // Get blockchain parent of the oldest branch block. - if ( ! fast_chain_.get_height(height, branch->hash())) { + auto const height = chain_.get_height(branch->hash()); + if ( ! height) { return false; } - branch->set_height(height); + branch->set_height(*height); return true; } -} // namespace kth::blockchain \ No newline at end of file +} // namespace kth::blockchain diff --git a/src/blockchain/src/pools/header_organizer.cpp b/src/blockchain/src/pools/header_organizer.cpp new file mode 100644 index 00000000..ee828be9 --- /dev/null +++ b/src/blockchain/src/pools/header_organizer.cpp @@ -0,0 +1,312 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include +#include +#include +#include + +namespace kth::blockchain { + +using namespace kth::domain::chain; + +// ============================================================================= +// Construction / Destruction +// ============================================================================= + +header_organizer::header_organizer(block_chain& chain, settings const& settings, + domain::config::network network, + header_cache_config config) + : chain_(chain) + , validator_(settings, network) + , config_(config) +{} + +header_organizer::~header_organizer() { + // Attempt to flush any pending headers on destruction + if (has_pending()) { + spdlog::warn("[header_organizer] Destroying with {} unflushed headers", + header_cache_.size()); + } +} + +// ============================================================================= +// Lifecycle +// ============================================================================= + +bool header_organizer::start() { + stopped_ = false; + return true; +} + +bool header_organizer::stop() { + stopped_ = true; + return true; +} + +// ============================================================================= +// Initialization +// ============================================================================= + +void header_organizer::initialize(size_t current_height, hash_digest const& current_tip_hash, + size_t expected_headers) { + std::lock_guard lock(mutex_); + + db_header_height_ = current_height; + db_tip_hash_ = current_tip_hash; + cache_tip_hash_ = current_tip_hash; + + // Pre-allocate cache if we know how many headers to expect + if (expected_headers > 0) { + auto const optimal_size = calculate_optimal_cache_size(expected_headers); + header_cache_.reserve(optimal_size); + hash_cache_.reserve(optimal_size); + + spdlog::info("[header_organizer] Initialized: DB height {}, cache pre-allocated for {} headers", + current_height, optimal_size); + } else { + spdlog::info("[header_organizer] Initialized: DB height {}", current_height); + } +} + +// ============================================================================= +// Header Addition +// ============================================================================= + +header_organize_result header_organizer::add_headers(domain::message::header::list const& headers) { + header_organize_result result; + + if (stopped()) { + result.error = error::service_stopped; + return result; + } + + if (headers.empty()) { + result.error = error::success; + return result; + } + + std::lock_guard lock(mutex_); + + spdlog::debug("[header_organizer] add_headers() called with {} headers", headers.size()); + + // Current tip is either from cache or from DB + hash_digest prev_hash = cache_tip_hash_; + size_t height = db_header_height_ + header_cache_.size() + 1; + + spdlog::debug("[header_organizer] Starting validation loop at height {}, cache_tip_hash: {}", + height, encode_hash(cache_tip_hash_)); + + if (!headers.empty()) { + spdlog::debug("[header_organizer] First header previous_block_hash: {}", + encode_hash(headers.front().previous_block_hash())); + } + + for (auto const& header : headers) { + // Validate header + auto const ec = validate(header, height, prev_hash); + if (ec) { + spdlog::debug("[header_organizer] Header validation failed at height {}: {}", + height, ec.message()); + result.error = ec; + break; + } + + // Compute hash and add to caches + auto const hash = header.hash(); + header_cache_.push_back(header); + hash_cache_.push_back(hash); + + prev_hash = hash; + cache_tip_hash_ = hash; + ++height; + ++result.headers_added; + + // Log progress every 500 headers + if (result.headers_added % 500 == 0) { + spdlog::debug("[header_organizer] Validated {} headers...", result.headers_added); + } + } + + spdlog::debug("[header_organizer] Validation complete: {} headers added", result.headers_added); + + result.cache_size = header_cache_.size(); + result.cache_memory_bytes = cache_memory_impl(); + + // Check if we should auto-flush + if (should_auto_flush()) { + spdlog::info("[header_organizer] Cache threshold reached ({} headers, {} MB), auto-flushing", + header_cache_.size(), + result.cache_memory_bytes / (1024 * 1024)); + + auto const flush_ec = flush_impl(); // Use _impl to avoid deadlock (we already hold mutex_) + if (flush_ec && result.error == error::success) { + result.error = flush_ec; + } + } + + return result; +} + +// ============================================================================= +// Flush to Database +// ============================================================================= + +code header_organizer::flush() { + std::lock_guard lock(mutex_); + return flush_impl(); +} + +// Internal version without lock (caller must hold mutex_) +code header_organizer::flush_impl() { + if (header_cache_.empty()) { + return error::success; + } + + auto const start_height = db_header_height_ + 1; + auto const count = header_cache_.size(); + + spdlog::debug("[header_organizer] Flushing {} headers to DB starting at height {}", + count, start_height); + + // Store all headers in batch + auto const ec = chain_.organize_headers_batch(header_cache_, start_height); + if (ec && ec != error::duplicate_block) { + spdlog::warn("[header_organizer] Failed to flush headers batch: {}", ec.message()); + return ec; + } + + // Update DB state + db_header_height_ = start_height + count - 1; + db_tip_hash_ = cache_tip_hash_; + + // Clear cache + header_cache_.clear(); + hash_cache_.clear(); + + spdlog::debug("[header_organizer] Flush complete, DB height now {}", db_header_height_); + + return error::success; +} + +// ============================================================================= +// Cache Access +// ============================================================================= + +std::vector header_organizer::get_cached_hashes() const { + std::lock_guard lock(mutex_); + return hash_cache_; +} + +void header_organizer::clear_cache() { + std::lock_guard lock(mutex_); + + header_cache_.clear(); + header_cache_.shrink_to_fit(); + hash_cache_.clear(); + hash_cache_.shrink_to_fit(); + + // Reset cache tip to DB tip + cache_tip_hash_ = db_tip_hash_; +} + +// ============================================================================= +// State Queries +// ============================================================================= + +size_t header_organizer::header_height() const { + std::lock_guard lock(mutex_); + return db_header_height_ + header_cache_.size(); +} + +hash_digest header_organizer::header_tip_hash() const { + std::lock_guard lock(mutex_); + return cache_tip_hash_; +} + +size_t header_organizer::cache_size() const { + std::lock_guard lock(mutex_); + return header_cache_.size(); +} + +size_t header_organizer::cache_memory() const { + std::lock_guard lock(mutex_); + return cache_memory_impl(); +} + +// Internal version without lock (caller must hold mutex_) +size_t header_organizer::cache_memory_impl() const { + auto const header_size = estimated_header_size(); + auto const hash_size = sizeof(hash_digest); + return static_cast( + (header_cache_.size() * header_size + hash_cache_.size() * hash_size) + * config_.memory_overhead + ); +} + +bool header_organizer::has_pending() const { + std::lock_guard lock(mutex_); + return !header_cache_.empty(); +} + +// ============================================================================= +// Memory Estimation +// ============================================================================= + +size_t header_organizer::calculate_optimal_cache_size(size_t items_needed) const { + // Header size + hash size per item + auto const item_size = estimated_header_size() + sizeof(hash_digest); + + auto const available = kth::get_available_system_memory(); + if (available == 0) { + // Fallback: use config max or reasonable default + auto const max_items = config_.max_cache_memory / item_size; + return std::min(items_needed, max_items); + } + + // Memory per item including overhead + auto const bytes_per_item = static_cast(item_size * config_.memory_overhead); + + // Use configured max or fraction of available memory (whichever is smaller) + auto const memory_fraction = available / 2; // Use at most 50% of available + auto const usable_memory = std::min(config_.max_cache_memory, memory_fraction); + + // Calculate how many items we can fit + auto const max_items = bytes_per_item > 0 ? usable_memory / bytes_per_item : 0; + + return std::min(items_needed, max_items); +} + +size_t header_organizer::estimated_header_size() { + // Header base size: version(4) + prev_hash(32) + merkle(32) + time(4) + bits(4) + nonce(4) = 80 bytes + // Plus std::vector overhead and alignment + return 80 + 48; // ~128 bytes estimated with overhead +} + +// ============================================================================= +// Internal Helpers +// ============================================================================= + +code header_organizer::validate(domain::chain::header const& header, size_t height, + hash_digest const& previous) const { + return validator_.validate(header, height, previous); +} + +bool header_organizer::should_auto_flush() const { + // Note: caller must hold mutex_ + auto const current_memory = static_cast( + (header_cache_.size() * estimated_header_size() + hash_cache_.size() * sizeof(hash_digest)) + * config_.memory_overhead + ); + + auto const threshold = static_cast(config_.max_cache_memory * config_.auto_flush_threshold); + return current_memory >= threshold; +} + +} // namespace kth::blockchain diff --git a/src/blockchain/src/pools/transaction_organizer.cpp b/src/blockchain/src/pools/transaction_organizer.cpp index 50aa57c0..60e4220e 100644 --- a/src/blockchain/src/pools/transaction_organizer.cpp +++ b/src/blockchain/src/pools/transaction_organizer.cpp @@ -6,18 +6,21 @@ #include #include +#include #include -#include #include #include #include -#include -#include +#include +#include #include #include #include +#include +#include + namespace kth::blockchain { using namespace std::placeholders; @@ -27,25 +30,26 @@ using namespace std::placeholders; // TODO(legacy): create priority pool at blockchain level and use in both organizers. #if defined(KTH_WITH_MEMPOOL) -transaction_organizer::transaction_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings, mining::mempool& mp) +transaction_organizer::transaction_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings, mining::mempool& mp) #else -transaction_organizer::transaction_organizer(prioritized_mutex& mutex, dispatcher& dispatch, threadpool& thread_pool, fast_chain& chain, settings const& settings) +transaction_organizer::transaction_organizer(prioritized_mutex& mutex, executor_type executor, size_t threads, threadpool& thread_pool, block_chain& chain, settings const& settings) #endif - : fast_chain_(chain) + : chain_(chain) , mutex_(mutex) , stopped_(true) , settings_(settings) - , dispatch_(dispatch) + , executor_(std::move(executor)) + , threads_(threads) , transaction_pool_(settings) #if defined(KTH_WITH_MEMPOOL) - , validator_(dispatch, fast_chain_, settings, mp) + , validator_(executor_, threads_, chain_, settings, mp) #else - , validator_(dispatch, fast_chain_, settings) + , validator_(executor_, threads_, chain_, settings) #endif - , subscriber_(std::make_shared(thread_pool, NAME)) - , ds_proof_subscriber_(std::make_shared(thread_pool, NAME)) + , broadcaster_(executor_) + , ds_proof_broadcaster_(executor_) #if defined(KTH_WITH_MEMPOOL) @@ -65,18 +69,16 @@ bool transaction_organizer::stopped() const { bool transaction_organizer::start() { stopped_ = false; - subscriber_->start(); - ds_proof_subscriber_->start(); + broadcaster_.start(); + ds_proof_broadcaster_.start(); validator_.start(); return true; } bool transaction_organizer::stop() { validator_.stop(); - subscriber_->stop(); - subscriber_->invoke(error::service_stopped, {}); - ds_proof_subscriber_->stop(); - ds_proof_subscriber_->invoke(error::service_stopped, {}); + broadcaster_.stop(); + ds_proof_broadcaster_.stop(); stopped_ = true; return true; } @@ -85,86 +87,59 @@ bool transaction_organizer::stop() { //----------------------------------------------------------------------------- // This is called from blockchain::transaction_validate. -void transaction_organizer::transaction_validate(transaction_const_ptr tx, result_handler handler) const { - auto const check_handler = std::bind(&transaction_organizer::validate_handle_check, this, _1, tx, handler); +::asio::awaitable transaction_organizer::transaction_validate(transaction_const_ptr tx) const { // Checks that are independent of chain state. - validator_.check(tx, check_handler); -} + auto ec = co_await validator_.check(tx); -// private -void transaction_organizer::validate_handle_check(code const& ec, transaction_const_ptr tx, result_handler handler) const { if (stopped()) { - handler(error::service_stopped); - return; + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + co_return ec; } - auto const accept_handler = std::bind(&transaction_organizer::validate_handle_accept, this, _1, tx, handler); // Checks that are dependent on chain state and prevouts. - validator_.accept(tx, accept_handler); -} + ec = co_await validator_.accept(tx); -// private -void transaction_organizer::validate_handle_accept(code const& ec, transaction_const_ptr tx, result_handler handler) const { if (stopped()) { - handler(error::service_stopped); - return; + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + co_return ec; } if (tx->fees() < price(tx)) { - handler(error::insufficient_fee); - return; + co_return error::insufficient_fee; } if (tx->is_dusty(settings_.minimum_output_satoshis)) { - handler(error::dusty_transaction); - return; + co_return error::dusty_transaction; } - auto const connect_handler = std::bind(&transaction_organizer::validate_handle_connect, this, _1, tx, handler); - // Checks that include script validation. - validator_.connect(tx, connect_handler); -} + ec = co_await validator_.connect(tx); -// private -void transaction_organizer::validate_handle_connect(code const& ec, transaction_const_ptr tx, result_handler handler) const { if (stopped()) { - handler(error::service_stopped); - return; - } - - if (ec) { - handler(ec); - return; + co_return error::service_stopped; } - handler(error::success); - return; + co_return ec; } // DSProof Organize sequence. //----------------------------------------------------------------------------- // This is called from blockchain::organize. -void transaction_organizer::organize(double_spend_proof_const_ptr ds_proof, result_handler handler) { +::asio::awaitable transaction_organizer::organize(double_spend_proof_const_ptr ds_proof) { // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_low_priority(); if (stopped()) { mutex_.unlock_low_priority(); - handler(error::service_stopped); - return; + co_return error::service_stopped; } ds_proofs_.try_emplace(hash(*ds_proof), ds_proof); @@ -175,195 +150,149 @@ void transaction_organizer::organize(double_spend_proof_const_ptr ds_proof, resu // This gets picked up by node DSProof-out protocol for announcement to peers. notify_ds_proof(ds_proof); - // Invoke caller handler outside of critical section. - handler(error::success); + co_return error::success; } // Transaction Organize sequence. //----------------------------------------------------------------------------- // This is called from blockchain::organize. -void transaction_organizer::organize(transaction_const_ptr tx, result_handler handler) { +::asio::awaitable transaction_organizer::organize(transaction_const_ptr tx) { // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_low_priority(); if (stopped()) { mutex_.unlock_low_priority(); - handler(error::service_stopped); - return; + co_return error::service_stopped; } - // Reset the reusable promise. - resume_ = std::promise(); - - result_handler const complete = std::bind(&transaction_organizer::signal_completion, this, _1); - auto const check_handler = std::bind(&transaction_organizer::handle_check, this, _1, tx, complete); - // Checks that are independent of chain state. - validator_.check(tx, check_handler); + auto ec = co_await validator_.check(tx); - // Wait on completion signal. - // This is necessary in order to continue on a non-priority thread. - // If we do not wait on the original thread there may be none left. - auto ec = resume_.get_future().get(); - - mutex_.unlock_low_priority(); - /////////////////////////////////////////////////////////////////////////// - - // Invoke caller handler outside of critical section. - handler(ec); -} - -// private -void transaction_organizer::signal_completion(code const& ec) { - // This must be protected so that it is properly cleared. - // Signal completion, which results in original handler invoke with code. - resume_.set_value(ec); -} - -// Verify sub-sequence. -//----------------------------------------------------------------------------- - -// private -void transaction_organizer::handle_check(code const& ec, transaction_const_ptr tx, result_handler handler) { if (stopped()) { - handler(error::service_stopped); - return; + mutex_.unlock_low_priority(); + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + mutex_.unlock_low_priority(); + co_return ec; } - auto const accept_handler = std::bind(&transaction_organizer::handle_accept, this, _1, tx, handler); - // Checks that are dependent on chain state and prevouts. - validator_.accept(tx, accept_handler); -} + ec = co_await validator_.accept(tx); -// private -void transaction_organizer::handle_accept(code const& ec, transaction_const_ptr tx, result_handler handler) { if (stopped()) { - handler(error::service_stopped); - return; + mutex_.unlock_low_priority(); + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + mutex_.unlock_low_priority(); + co_return ec; } if (tx->fees() < price(tx)) { - handler(error::insufficient_fee); - return; + mutex_.unlock_low_priority(); + co_return error::insufficient_fee; } if (tx->is_dusty(settings_.minimum_output_satoshis)) { - handler(error::dusty_transaction); - return; + mutex_.unlock_low_priority(); + co_return error::dusty_transaction; } - auto const connect_handler = std::bind(&transaction_organizer::handle_connect, this, _1, tx, handler); - // Checks that include script validation. - validator_.connect(tx, connect_handler); -} + ec = co_await validator_.connect(tx); -// private -void transaction_organizer::handle_connect(code const& ec, transaction_const_ptr tx, result_handler handler) { if (stopped()) { - handler(error::service_stopped); - return; + mutex_.unlock_low_priority(); + co_return error::service_stopped; } if (ec) { - handler(ec); - return; + mutex_.unlock_low_priority(); + co_return ec; } // TODO: create a simulated validation path that does not block others. if (tx->validation.simulate) { - handler(error::success); - return; + mutex_.unlock_low_priority(); + co_return error::success; } #if defined(KTH_WITH_MEMPOOL) auto res = mempool_.add(*tx); if (res == error::double_spend_mempool || res == error::double_spend_blockchain) { - handler(res); - return; + mutex_.unlock_low_priority(); + co_return res; } // spdlog::info("[blockchain] Transaction {} added to mempool.", encode_hash(tx->hash())); #endif #if ! defined(KTH_DB_READONLY) - auto const pushed_handler = std::bind(&transaction_organizer::handle_pushed, this, _1, tx, handler); //######################################################################### - fast_chain_.push(tx, dispatch_, pushed_handler); + auto push_ec = co_await chain_.push(tx); + if (push_ec) { + mutex_.unlock_low_priority(); + co_return push_ec; + } //######################################################################### #endif -} -#if ! defined(KTH_DB_READONLY) -// private -void transaction_organizer::handle_pushed(code const& ec, transaction_const_ptr tx, result_handler handler) { - if (ec) { - spdlog::critical("[blockchain] Failure writing transaction to store, is now corrupted: {}", ec.message()); - handler(ec); - return; - } + mutex_.unlock_low_priority(); + /////////////////////////////////////////////////////////////////////////// // This gets picked up by node tx-out protocol for announcement to peers. notify(tx); - handler(error::success); + co_return error::success; } -#endif // ! defined(KTH_DB_READONLY) // Subscription. //----------------------------------------------------------------------------- // private void transaction_organizer::notify(transaction_const_ptr tx) { - // This invokes handlers within the criticial section (deadlock risk). - subscriber_->invoke(error::success, tx); + broadcaster_.publish(tx); } -void transaction_organizer::notify_ds_proof(double_spend_proof_const_ptr tx) { - // This invokes handlers within the criticial section (deadlock risk). - ds_proof_subscriber_->invoke(error::success, tx); +void transaction_organizer::notify_ds_proof(double_spend_proof_const_ptr ds_proof) { + ds_proof_broadcaster_.publish(ds_proof); } -void transaction_organizer::subscribe(transaction_handler&& handler) { - subscriber_->subscribe(std::move(handler), error::service_stopped, {}); +transaction_organizer::transaction_broadcaster::channel_ptr transaction_organizer::subscribe() { + return broadcaster_.subscribe(); } -void transaction_organizer::subscribe_ds_proof(ds_proof_handler&& handler) { - ds_proof_subscriber_->subscribe(std::move(handler), error::service_stopped, {}); +transaction_organizer::ds_proof_broadcaster::channel_ptr transaction_organizer::subscribe_ds_proof() { + return ds_proof_broadcaster_.subscribe(); } -void transaction_organizer::unsubscribe() { - subscriber_->relay(error::success, {}); +void transaction_organizer::unsubscribe(transaction_broadcaster::channel_ptr const& channel) { + broadcaster_.unsubscribe(channel); } -void transaction_organizer::unsubscribe_ds_proof() { - ds_proof_subscriber_->relay(error::success, {}); +void transaction_organizer::unsubscribe_ds_proof(ds_proof_broadcaster::channel_ptr const& channel) { + ds_proof_broadcaster_.unsubscribe(channel); } // Queries. //----------------------------------------------------------------------------- -void transaction_organizer::fetch_template(merkle_block_fetch_handler handler) const { - transaction_pool_.fetch_template(handler); +awaitable_expected> +transaction_organizer::fetch_template() const { + co_return co_await transaction_pool_.fetch_template(); } -void transaction_organizer::fetch_mempool(size_t maximum, inventory_fetch_handler handler) const { - transaction_pool_.fetch_mempool(maximum, handler); +awaitable_expected +transaction_organizer::fetch_mempool(size_t maximum) const { + co_return co_await transaction_pool_.fetch_mempool(maximum); } -void transaction_organizer::fetch_ds_proof(hash_digest const& hash, ds_proof_fetch_handler handler) const { +awaitable_expected +transaction_organizer::fetch_ds_proof(hash_digest const& hash) const { // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_low_priority(); @@ -371,8 +300,7 @@ void transaction_organizer::fetch_ds_proof(hash_digest const& hash, ds_proof_fet auto it = ds_proofs_.find(hash); if (it == ds_proofs_.end()) { mutex_.unlock_low_priority(); - handler(error::not_found, nullptr); - return; + co_return std::unexpected(error::not_found); } auto const res = it->second; @@ -380,8 +308,7 @@ void transaction_organizer::fetch_ds_proof(hash_digest const& hash, ds_proof_fet mutex_.unlock_low_priority(); /////////////////////////////////////////////////////////////////////////// - // Invoke caller handler outside of critical section. - handler(error::success, res); + co_return res; } // Utility. @@ -403,4 +330,4 @@ uint64_t transaction_organizer::price(transaction_const_ptr tx) const { return std::max(uint64_t(1), uint64_t(byte + sigop)); } -} // namespace kth::blockchain \ No newline at end of file +} // namespace kth::blockchain diff --git a/src/blockchain/src/pools/transaction_pool.cpp b/src/blockchain/src/pools/transaction_pool.cpp index 0182ade1..72abecc1 100644 --- a/src/blockchain/src/pools/transaction_pool.cpp +++ b/src/blockchain/src/pools/transaction_pool.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -18,23 +19,22 @@ namespace kth::blockchain { // exmaple implementation simply tests all txs in a new block against // transactions in previous blocks. -transaction_pool::transaction_pool(settings const& settings) - ////: reject_conflicts_(settings.reject_conflicts), - //// minimum_fee_(settings.minimum_fee_satoshis) +transaction_pool::transaction_pool(settings const& /*settings*/) {} // TODO(legacy): implement block template discovery. -void transaction_pool::fetch_template(merkle_block_fetch_handler handler) const { +awaitable_expected> +transaction_pool::fetch_template() const { size_t const height = max_size_t; auto const block = std::make_shared(); - handler(error::success, block, height); + co_return std::pair{block, height}; } // TODO(legacy): implement mempool message payload discovery. -void transaction_pool::fetch_mempool(size_t maximum, - inventory_fetch_handler handler) const { +awaitable_expected +transaction_pool::fetch_mempool(size_t /*maximum*/) const { auto const empty = std::make_shared(); - handler(error::success, empty); + co_return empty; } } // namespace kth::blockchain diff --git a/src/blockchain/src/populate/populate_base.cpp b/src/blockchain/src/populate/populate_base.cpp index 84bef096..8d77b17d 100644 --- a/src/blockchain/src/populate/populate_base.cpp +++ b/src/blockchain/src/populate/populate_base.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace kth::blockchain { @@ -15,39 +15,34 @@ namespace kth::blockchain { using namespace kd::chain; using namespace kth::database; -#define NAME "populate_base" - - // Database access is limited to: // spend: { spender } // transaction: { exists, height, position, output } -populate_base::populate_base(dispatcher& dispatch, fast_chain const& chain) - : dispatch_(dispatch) - , fast_chain_(chain) +populate_base::populate_base(executor_type executor, size_t threads, block_chain const& chain) + : executor_(std::move(executor)) + , threads_(threads) + , chain_(chain) {} // This is the only necessary file system read in block/tx validation. -void populate_base::populate_duplicate(size_t branch_height, const domain::chain::transaction& tx, bool require_confirmed) const { +void populate_base::populate_duplicate(size_t branch_height, domain::chain::transaction const& tx, bool require_confirmed) const { //Knuth: We are not validating tx duplication tx.validation.duplicate = false; } -void populate_base::populate_pooled(const domain::chain::transaction& tx, uint32_t forks) const { - size_t height; - size_t position; - - if (fast_chain_.get_transaction_position(height, position, tx.hash(), false) - - && (position == position_max)) { - - tx.validation.pooled = true; - tx.validation.current = (height == forks); - return; - } - +void populate_base::populate_pooled(domain::chain::transaction const& tx, uint32_t forks) const { tx.validation.pooled = false; tx.validation.current = false; + auto const result = chain_.get_transaction_position(tx.hash(), false); + if ( ! result) { + return; + } + if (result->second != position_max) { + return; + } + tx.validation.pooled = true; + tx.validation.current = (result->first == forks); } // Unspent outputs are cached by the store. If the cache is large enough this @@ -68,9 +63,14 @@ void populate_base::populate_prevout(size_t branch_height, output_point const& o } //TODO(fernando): check the value of the parameters: branch_height and require_confirmed - if ( ! fast_chain_.get_utxo(prevout.cache, prevout.height, prevout.median_time_past, prevout.coinbase, outpoint, branch_height)) { + auto const utxo = chain_.get_utxo(outpoint, branch_height); + if ( ! utxo) { return; } + prevout.cache = utxo->output; + prevout.height = utxo->height; + prevout.median_time_past = utxo->median_time_past; + prevout.coinbase = utxo->coinbase; // BUGBUG: Spends are not marked as spent by unconfirmed transactions. // So tx pool transactions currently have no double spend limitation. diff --git a/src/blockchain/src/populate/populate_block.cpp b/src/blockchain/src/populate/populate_block.cpp index 66ac700d..1e03326c 100644 --- a/src/blockchain/src/populate/populate_block.cpp +++ b/src/blockchain/src/populate/populate_block.cpp @@ -5,47 +5,49 @@ #include #include +#include #include #include +#include -#include +#include #include #include -#include +#include +#include +#include +#include namespace kth::blockchain { using namespace kd::chain; using namespace kd::machine; -#define NAME "populate_block" - // Database access is limited to calling populate_base. #if defined(KTH_WITH_MEMPOOL) -populate_block::populate_block(dispatcher& dispatch, fast_chain const& chain, bool relay_transactions, mining::mempool const& mp) +populate_block::populate_block(executor_type executor, size_t threads, block_chain const& chain, bool relay_transactions, mining::mempool const& mp) #else -populate_block::populate_block(dispatcher& dispatch, fast_chain const& chain, bool relay_transactions) +populate_block::populate_block(executor_type executor, size_t threads, block_chain const& chain, bool relay_transactions) #endif - : populate_base(dispatch, chain) + : populate_base(std::move(executor), threads, chain) , relay_transactions_(relay_transactions) #if defined(KTH_WITH_MEMPOOL) , mempool_(mp) #endif {} -void populate_block::populate(branch::const_ptr branch, result_handler&& handler) const { +::asio::awaitable populate_block::populate(branch::const_ptr branch) const { auto const block = branch->top(); KTH_ASSERT(block); auto const state = block->validation.state; KTH_ASSERT(state); - // Return if this blocks is under a checkpoint, block state not requried. + // Return if this blocks is under a checkpoint, block state not required. if (state->is_under_checkpoint()) { - handler(error::success); - return; + co_return error::success; } // Handle the coinbase as a special case tx. @@ -55,12 +57,10 @@ void populate_block::populate(branch::const_ptr branch, result_handler&& handler // Return if there are no non-coinbase inputs to validate. if (non_coinbase_inputs == 0) { - handler(error::success); - return; + co_return error::success; } - auto const buckets = std::min(dispatch_.size(), non_coinbase_inputs); - auto const join_handler = synchronize(std::move(handler), buckets, NAME); + auto const buckets = std::min(threads_, non_coinbase_inputs); KTH_ASSERT(buckets != 0); auto branch_utxo = create_branch_utxo_set(branch); @@ -69,13 +69,39 @@ void populate_block::populate(branch::const_ptr branch, result_handler&& handler auto validated_txs = mempool_.get_validated_txs_high(); #endif + // Use a channel to collect results from parallel tasks + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor_, buckets); + + // Launch parallel tasks for (size_t bucket = 0; bucket < buckets; ++bucket) { #if defined(KTH_WITH_MEMPOOL) - dispatch_.concurrent(&populate_block::populate_transactions, this, branch, bucket, buckets, branch_utxo, validated_txs, join_handler); + ::asio::post(executor_, [this, branch, bucket, buckets, branch_utxo, validated_txs, channel]() { + auto result = populate_transactions_sync(branch, bucket, buckets, branch_utxo, validated_txs); + channel->try_send(std::error_code{}, result); + }); #else - dispatch_.concurrent(&populate_block::populate_transactions, this, branch, bucket, buckets, branch_utxo, join_handler); + ::asio::post(executor_, [this, branch, bucket, buckets, branch_utxo, channel]() { + auto result = populate_transactions_sync(branch, bucket, buckets, branch_utxo); + channel->try_send(std::error_code{}, result); + }); #endif } + + // Wait for all results - return first error or success if all succeed + code final_result = error::success; + for (size_t i = 0; i < buckets; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + // Channel error - shouldn't happen + co_return error::operation_failed; + } + if (result != error::success && final_result == error::success) { + final_result = result; + } + } + + co_return final_result; } // Initialize the coinbase input for subsequent validation. @@ -114,22 +140,24 @@ void populate_block::populate_coinbase(branch::const_ptr branch, block_const_ptr } populate_block::utxo_pool_t populate_block::get_reorg_subset_conditionally(size_t first_height, size_t& out_chain_top) const { - - if ( ! fast_chain_.get_last_height(out_chain_top)) { + auto const heights = chain_.get_last_heights(); + if ( ! heights) { out_chain_top = 0; return {}; } + out_chain_top = heights->first; // header_height + if (first_height > out_chain_top) { return {}; } - auto p = fast_chain_.get_utxo_pool_from(first_height, out_chain_top); - if ( ! p.first) { + auto p = chain_.get_utxo_pool_from(first_height, out_chain_top); + if ( ! p) { return {}; } - return std::move(p.second); + return std::move(*p); } @@ -153,11 +181,10 @@ void populate_block::populate_transaction_inputs(branch::const_ptr branch, domai } #if defined(KTH_WITH_MEMPOOL) -void populate_block::populate_transactions(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo, mining::mempool::hash_index_t const& validated_txs, result_handler handler) const { +code populate_block::populate_transactions_sync(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo, mining::mempool::hash_index_t const& validated_txs) const { #else -void populate_block::populate_transactions(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo, result_handler handler) const { +code populate_block::populate_transactions_sync(branch::const_ptr branch, size_t bucket, size_t buckets, local_utxo_set_t const& branch_utxo) const { #endif - // TODO(fernando): check how to replace it with UTXO KTH_ASSERT(bucket < buckets); auto const block = branch->top(); auto const branch_height = branch->height(); @@ -183,7 +210,6 @@ void populate_block::populate_transactions(branch::const_ptr branch, size_t buck // unless tx relay is disabled. In that case duplication is unlikely. //--------------------------------------------------------------------- - //TODO(fernando): check again why this is not implemented? if (relay_transactions_) { populate_base::populate_pooled(tx, forks); } @@ -223,7 +249,7 @@ void populate_block::populate_transactions(branch::const_ptr branch, size_t buck #endif // defined(KTH_WITH_MEMPOOL) } - handler(error::success); + return error::success; } void populate_block::populate_from_reorg_subset(output_point const& outpoint, utxo_pool_t const& reorg_subset) const { @@ -254,4 +280,4 @@ void populate_block::populate_prevout(branch::const_ptr branch, output_point con } } -} // namespace kth::blockchain \ No newline at end of file +} // namespace kth::blockchain diff --git a/src/blockchain/src/populate/populate_chain_state.cpp b/src/blockchain/src/populate/populate_chain_state.cpp index 6cbbb79b..eca77ff9 100644 --- a/src/blockchain/src/populate/populate_chain_state.cpp +++ b/src/blockchain/src/populate/populate_chain_state.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include @@ -30,7 +30,7 @@ static constexpr uint32_t unspecified = max_uint32; // get_last_height // block: { hash, bits, version, timestamp } -populate_chain_state::populate_chain_state(fast_chain const& chain, settings const& settings, domain::config::network network) +populate_chain_state::populate_chain_state(block_chain const& chain, settings const& settings, domain::config::network network) : #if defined(KTH_CURRENCY_BCH) settings_(settings), @@ -38,7 +38,7 @@ populate_chain_state::populate_chain_state(fast_chain const& chain, settings con configured_forks_(settings.enabled_forks()) , checkpoints_(infrastructure::config::checkpoint::sort(settings.checkpoints)) , network_(network) - , fast_chain_(chain) + , chain_(chain) {} inline @@ -48,21 +48,53 @@ bool is_transaction_pool(branch::const_ptr branch) { bool populate_chain_state::get_bits(uint32_t& out_bits, size_t height, branch::const_ptr branch) const { // branch returns false only if the height is out of range. - return branch->get_bits(out_bits, height) || fast_chain_.get_bits(out_bits, height); + if (branch->get_bits(out_bits, height)) { + return true; + } + auto result = chain_.get_bits(height); + if ( ! result) { + return false; + } + out_bits = *result; + return true; } bool populate_chain_state::get_version(uint32_t& out_version, size_t height, branch::const_ptr branch) const { // branch returns false only if the height is out of range. - return branch->get_version(out_version, height) || fast_chain_.get_version(out_version, height); + if (branch->get_version(out_version, height)) { + return true; + } + auto result = chain_.get_version(height); + if ( ! result) { + return false; + } + out_version = *result; + return true; } bool populate_chain_state::get_timestamp(uint32_t& out_timestamp, size_t height, branch::const_ptr branch) const { // branch returns false only if the height is out of range. - return branch->get_timestamp(out_timestamp, height) || fast_chain_.get_timestamp(out_timestamp, height); + if (branch->get_timestamp(out_timestamp, height)) { + return true; + } + auto result = chain_.get_timestamp(height); + if ( ! result) { + return false; + } + out_timestamp = *result; + return true; } bool populate_chain_state::get_block_hash(hash_digest& out_hash, size_t height, branch::const_ptr branch) const { - return branch->get_block_hash(out_hash, height) || fast_chain_.get_block_hash(out_hash, height); + if (branch->get_block_hash(out_hash, height)) { + return true; + } + auto result = chain_.get_block_hash(height); + if ( ! result) { + return false; + } + out_hash = *result; + return true; } bool populate_chain_state::populate_bits(chain_state::data& data, chain_state::map const& map, branch::const_ptr branch) const { @@ -232,21 +264,18 @@ chain_state::assert_anchor_block_info_t populate_chain_state::get_assert_anchor_ #endif // defined(KTH_CURRENCY_BCH) chain_state::ptr populate_chain_state::populate() const { - size_t top; - if ( ! fast_chain_.get_last_height(top)) { + auto const heights = chain_.get_last_heights(); + if ( ! heights) { spdlog::error("[blockchain] Failed to populate chain state, last height."); return {}; } - auto opt = fast_chain_.get_header_and_abla_state(top); - if ( ! opt) { - spdlog::error("[blockchain] Failed to populate chain state, last header."); - return {}; - } - auto [last_header, block_size, control_block_size, elastic_buffer_size] = *opt; - if ( ! last_header.is_valid()) { + auto const top = heights->first; // header_height + auto const header_result = chain_.get_header_and_abla_state(top); + if ( ! header_result) { spdlog::error("[blockchain] Failed to populate chain state, last header."); return {}; } + auto const& [last_header, block_size, control_block_size, elastic_buffer_size] = *header_result; chain_state::data data; data.hash = null_hash; diff --git a/src/blockchain/src/populate/populate_transaction.cpp b/src/blockchain/src/populate/populate_transaction.cpp index c716d381..1f705688 100644 --- a/src/blockchain/src/populate/populate_transaction.cpp +++ b/src/blockchain/src/populate/populate_transaction.cpp @@ -10,11 +10,14 @@ #include #include -#include +#include #include #include -#include +#include +#include +#include +#include namespace kth::blockchain { @@ -26,17 +29,17 @@ using namespace std::placeholders; // Database access is limited to calling populate_base. #if defined(KTH_WITH_MEMPOOL) -populate_transaction::populate_transaction(dispatcher& dispatch, fast_chain const& chain, mining::mempool const& mp) - : populate_base(dispatch, chain) +populate_transaction::populate_transaction(executor_type executor, size_t threads, block_chain const& chain, mining::mempool const& mp) + : populate_base(std::move(executor), threads, chain) , mempool_(mp) {} #else -populate_transaction::populate_transaction(dispatcher& dispatch, fast_chain const& chain) - : populate_base(dispatch, chain) +populate_transaction::populate_transaction(executor_type executor, size_t threads, block_chain const& chain) + : populate_base(std::move(executor), threads, chain) {} #endif -void populate_transaction::populate(transaction_const_ptr tx, result_handler&& handler) const { +::asio::awaitable populate_transaction::populate(transaction_const_ptr tx) const { auto const state = tx->validation.state; KTH_ASSERT(state); @@ -57,28 +60,48 @@ void populate_transaction::populate(transaction_const_ptr tx, result_handler&& h // Because txs include no proof of work we much short circuit here. // Otherwise a peer can flood us with repeat transactions to validate. if (tx->validation.duplicate) { - handler(error::unspent_duplicate); - return; + co_return error::unspent_duplicate; } auto const total_inputs = tx->inputs().size(); // Return if there are no inputs to validate (will fail later). if (total_inputs == 0) { - handler(error::success); - return; + co_return error::success; } - auto const buckets = std::min(dispatch_.size(), total_inputs); - auto const join_handler = synchronize(std::move(handler), buckets, NAME); + auto const buckets = std::min(threads_, total_inputs); KTH_ASSERT(buckets != 0); + // Use a channel to collect results from parallel tasks + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor_, buckets); + + // Launch parallel tasks for (size_t bucket = 0; bucket < buckets; ++bucket) { - dispatch_.concurrent(&populate_transaction::populate_inputs, this, tx, chain_height, bucket, buckets, join_handler); + ::asio::post(executor_, [this, tx, chain_height, bucket, buckets, channel]() { + auto result = populate_inputs_sync(tx, chain_height, bucket, buckets); + channel->try_send(std::error_code{}, result); + }); + } + + // Wait for all results - return first error or success if all succeed + code final_result = error::success; + for (size_t i = 0; i < buckets; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + // Channel error - shouldn't happen + co_return error::operation_failed; + } + if (result != error::success && final_result == error::success) { + final_result = result; + } } + + co_return final_result; } -void populate_transaction::populate_inputs(transaction_const_ptr tx, size_t chain_height, size_t bucket, size_t buckets, result_handler handler) const { +code populate_transaction::populate_inputs_sync(transaction_const_ptr tx, size_t chain_height, size_t bucket, size_t buckets) const { KTH_ASSERT(bucket < buckets); auto const& inputs = tx->inputs(); @@ -99,7 +122,7 @@ void populate_transaction::populate_inputs(transaction_const_ptr tx, size_t chai } - handler(error::success); + return error::success; } } // namespace kth::blockchain diff --git a/src/blockchain/src/validate/validate_block.cpp b/src/blockchain/src/validate/validate_block.cpp index 00d81aea..395cbe62 100644 --- a/src/blockchain/src/validate/validate_block.cpp +++ b/src/blockchain/src/validate/validate_block.cpp @@ -10,44 +10,44 @@ #include #include -#include +#include #include #include #include #include #include -#include +#include +#include +#include +#include namespace kth::blockchain { using namespace kd::chain; using namespace kd::machine; -using namespace std::placeholders; - -#define NAME "validate_block" // Database access is limited to: populator: // spend: { spender } // block: { bits, version, timestamp } // transaction: { exists, height, output } -// If the priority threadpool is shut down when this is running the handlers -// will never be invoked, resulting in a threadpool.join indefinite hang. - #if defined(KTH_WITH_MEMPOOL) -validate_block::validate_block(dispatcher& dispatch, fast_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool const& mp) +validate_block::validate_block(executor_type executor, size_t threads, block_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions, mining::mempool const& mp) #else -validate_block::validate_block(dispatcher& dispatch, fast_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions) +validate_block::validate_block(executor_type executor, size_t threads, block_chain const& chain, settings const& settings, domain::config::network network, bool relay_transactions) #endif : stopped_(true) - , fast_chain_(chain) + , chain_(chain) , network_(network) - , priority_dispatch_(dispatch) + , executor_(std::move(executor)) + , threads_(threads) + , hits_(0) + , queries_(0) #if defined(KTH_WITH_MEMPOOL) - , block_populator_(dispatch, chain, relay_transactions, mp) + , block_populator_(executor_, threads_, chain, relay_transactions, mp) #else - , block_populator_(dispatch, chain, relay_transactions) + , block_populator_(executor_, threads_, chain, relay_transactions) #endif {} @@ -66,33 +66,54 @@ void validate_block::stop() { //----------------------------------------------------------------------------- // These checks are context free. -void validate_block::check(block_const_ptr block, result_handler handler) const { +::asio::awaitable validate_block::check(block_const_ptr block) const { // The block hasn't been checked yet. if (block->transactions().empty()) { - handler(error::success); - return; + co_return error::success; } - result_handler complete_handler = std::bind(&validate_block::handle_checked, this, _1, block, handler); - // TODO: make configurable for each parallel segment. // This one is more efficient with one thread than parallel. - auto const threads = std::min(size_t(1), priority_dispatch_.size()); + auto const threads = std::min(size_t(1), threads_); auto const count = block->transactions().size(); auto const buckets = std::min(threads, count); KTH_ASSERT(buckets != 0); - auto const join_handler = synchronize(std::move(complete_handler), buckets, NAME "_check"); + // Use a channel to collect results from parallel tasks + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor_, buckets); + // Launch parallel tasks for (size_t bucket = 0; bucket < buckets; ++bucket) { - priority_dispatch_.concurrent(&validate_block::check_block, this, block, bucket, buckets, join_handler); + ::asio::post(executor_, [this, block, bucket, buckets, channel]() { + auto result = check_block_bucket(block, bucket, buckets); + channel->try_send(std::error_code{}, result); + }); + } + + // Wait for all results + code final_result = error::success; + for (size_t i = 0; i < buckets; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return error::operation_failed; + } + if (result != error::success && final_result == error::success) { + final_result = result; + } } + + if (final_result) { + co_return final_result; + } + + // Run context free checks, sets time internally. + co_return block->check(); } -void validate_block::check_block(block_const_ptr block, size_t bucket, size_t buckets, result_handler handler) const { +code validate_block::check_block_bucket(block_const_ptr block, size_t bucket, size_t buckets) const { if (stopped()) { - handler(error::service_stopped); - return; + return error::service_stopped; } auto const& txs = block->transactions(); @@ -102,24 +123,14 @@ void validate_block::check_block(block_const_ptr block, size_t bucket, size_t bu txs[tx].hash(); } - handler(error::success); -} - -void validate_block::handle_checked(code const& ec, block_const_ptr block, result_handler handler) const { - if (ec) { - handler(ec); - return; - } - - // Run context free checks, sets time internally. - handler(block->check()); + return error::success; } // Accept sequence. //----------------------------------------------------------------------------- // These checks require chain state, and block state if not under checkpoint. -void validate_block::accept(branch::const_ptr branch, result_handler handler) const { +::asio::awaitable validate_block::accept(branch::const_ptr branch) const { auto const block = branch->top(); KTH_ASSERT(block); @@ -127,26 +138,21 @@ void validate_block::accept(branch::const_ptr branch, result_handler handler) co block->validation.start_populate = asio::steady_clock::now(); // Populate chain state for the next block. - block->validation.state = fast_chain_.chain_state(branch); + block->validation.state = chain_.chain_state(branch); if ( ! block->validation.state) { - handler(error::block_validation_state_failed); - return; + co_return error::block_validation_state_failed; } // Populate block state for the top block (others are valid). - block_populator_.populate(branch, std::bind(&validate_block::handle_populated, this, _1, block, handler)); -} + auto const populate_ec = co_await block_populator_.populate(branch); -void validate_block::handle_populated(code const& ec, block_const_ptr block, result_handler handler) const { if (stopped()) { - handler(error::service_stopped); - return; + co_return error::service_stopped; } - if (ec) { - handler(ec); - return; + if (populate_ec) { + co_return populate_ec; } auto const height = block->validation.state->height(); @@ -155,8 +161,7 @@ void validate_block::handle_populated(code const& ec, block_const_ptr block, res auto const error_code = block->accept(false); if (error_code) { - handler(error_code); - return; + co_return error_code; } auto const sigops = std::make_shared(0); @@ -168,32 +173,64 @@ void validate_block::handle_populated(code const& ec, block_const_ptr block, res auto const bip141 = state->is_enabled(domain::machine::rule_fork::bip141_rule); #endif - result_handler complete_handler = std::bind(&validate_block::handle_accepted, this, _1, block, sigops, bip141, handler); - if (state->is_under_checkpoint()) { - complete_handler(error::success); - return; + co_return error::success; } auto const count = block->transactions().size(); auto const bip16 = state->is_enabled(domain::machine::rule_fork::bip16_rule); - auto const buckets = std::min(priority_dispatch_.size(), count); + auto const buckets = std::min(threads_, count); KTH_ASSERT(buckets != 0); - auto const join_handler = synchronize(std::move(complete_handler), buckets, NAME "_accept"); + // Use a channel to collect results from parallel tasks + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor_, buckets); + // Launch parallel tasks for (size_t bucket = 0; bucket < buckets; ++bucket) { - priority_dispatch_.concurrent(&validate_block::accept_transactions, this, block, bucket, buckets, sigops, bip16, bip141, join_handler); + ::asio::post(executor_, [this, block, bucket, buckets, sigops, bip16, bip141, channel]() { + auto result = accept_transactions_bucket(block, bucket, buckets, sigops, bip16, bip141); + channel->try_send(std::error_code{}, result); + }); + } + + // Wait for all results + code accept_result = error::success; + for (size_t i = 0; i < buckets; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return error::operation_failed; + } + if (result != error::success && accept_result == error::success) { + accept_result = result; + } } + + if (accept_result) { + co_return accept_result; + } + + // Check sigops limit +#if defined(KTH_CURRENCY_BCH) + if (block->validation.state->is_fermat_enabled()) { + co_return error::success; + } + + size_t allowed_sigops = get_allowed_sigops(block->serialized_size(1)); + auto const exceeded = *sigops > allowed_sigops; +#else + auto const max_sigops = bip141 ? max_fast_sigops : get_allowed_sigops(block->serialized_size(1)); + auto const exceeded = *sigops > max_sigops; +#endif + co_return exceeded ? error::block_embedded_sigop_limit : error::success; } -void validate_block::accept_transactions(block_const_ptr block, size_t bucket, size_t buckets, atomic_counter_ptr sigops, bool bip16, bool bip141, result_handler handler) const { +code validate_block::accept_transactions_bucket(block_const_ptr block, size_t bucket, size_t buckets, atomic_counter_ptr sigops, bool bip16, bool bip141) const { #if defined(KTH_CURRENCY_BCH) bip141 = false; #endif if (stopped()) { - handler(error::service_stopped); - return; + return error::service_stopped; } code ec(error::success); @@ -205,43 +242,19 @@ void validate_block::accept_transactions(block_const_ptr block, size_t bucket, s for (auto tx = bucket; tx < count && !ec; tx = ceiling_add(tx, buckets)) { auto const& transaction = txs[tx]; if ( ! transaction.validation.validated) { - // spdlog::info("[blockchain] Transaction {} has to be validated.", encode_hash(transaction.hash())); ec = transaction.accept(state, false); - } else { - // spdlog::info("[blockchain] Transaction {} validation could be skiped.", encode_hash(transaction.hash())); } *sigops += transaction.signature_operations(bip16, bip141); } - handler(ec); -} - -void validate_block::handle_accepted(code const& ec, block_const_ptr block, atomic_counter_ptr sigops, bool bip141, result_handler handler) const { - if (ec) { - handler(ec); - return; - } - -#if defined(KTH_CURRENCY_BCH) - if (block->validation.state->is_fermat_enabled()) { - handler(error::success); - return; - } - - size_t allowed_sigops = get_allowed_sigops(block->serialized_size(1)); - auto const exceeded = *sigops > allowed_sigops; -#else - auto const max_sigops = bip141 ? max_fast_sigops : get_allowed_sigops(block->serialized_size(1)); - auto const exceeded = *sigops > max_sigops; -#endif - handler(exceeded ? error::block_embedded_sigop_limit : error::success); + return ec; } // Connect sequence. //----------------------------------------------------------------------------- // These checks require chain state, block state and perform script validation. -void validate_block::connect(branch::const_ptr branch, result_handler handler) const { +::asio::awaitable validate_block::connect(branch::const_ptr branch) const { auto const block = branch->top(); KTH_ASSERT(block && block->validation.state); @@ -249,36 +262,52 @@ void validate_block::connect(branch::const_ptr branch, result_handler handler) c block->validation.start_connect = asio::steady_clock::now(); if (block->validation.state->is_under_checkpoint()) { - handler(error::success); - return; + co_return error::success; } auto const non_coinbase_inputs = block->total_inputs(false); // Return if there are no non-coinbase inputs to validate. if (non_coinbase_inputs == 0) { - handler(error::success); - return; + co_return error::success; } // Reset statistics for each block (treat coinbase as cached). hits_ = 0; queries_ = 0; - result_handler complete_handler = std::bind(&validate_block::handle_connected, this, _1, block, handler); - - auto const threads = priority_dispatch_.size(); - auto const buckets = std::min(threads, non_coinbase_inputs); + auto const buckets = std::min(threads_, non_coinbase_inputs); KTH_ASSERT(buckets != 0); - auto const join_handler = synchronize(std::move(complete_handler), buckets, NAME "_validate"); + // Use a channel to collect results from parallel tasks + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor_, buckets); + // Launch parallel tasks for (size_t bucket = 0; bucket < buckets; ++bucket) { - priority_dispatch_.concurrent(&validate_block::connect_inputs, this, block, bucket, buckets, join_handler); + ::asio::post(executor_, [this, block, bucket, buckets, channel]() { + auto result = connect_inputs_bucket(block, bucket, buckets); + channel->try_send(std::error_code{}, result); + }); } + + // Wait for all results + code connect_result = error::success; + for (size_t i = 0; i < buckets; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return error::operation_failed; + } + if (result != error::success && connect_result == error::success) { + connect_result = result; + } + } + + block->validation.cache_efficiency = hit_rate(); + co_return connect_result; } -void validate_block::connect_inputs(block_const_ptr block, size_t bucket, size_t buckets, result_handler handler) const { +code validate_block::connect_inputs_bucket(block_const_ptr block, size_t bucket, size_t buckets) const { KTH_ASSERT(bucket < buckets); code ec(error::success); auto const forks = block->validation.state->enabled_forks(); @@ -289,8 +318,6 @@ void validate_block::connect_inputs(block_const_ptr block, size_t bucket, size_t size_t block_sigchecks = 0; #endif - //TODO(fernando): count the coinbase sigchecks - // Must skip coinbase here as it is already accounted for. for (auto tx = txs.begin() + 1; tx != txs.end(); ++tx) { ++queries_; @@ -302,7 +329,6 @@ void validate_block::connect_inputs(block_const_ptr block, size_t bucket, size_t } // The tx was validated before its insertion in the mempool - // TODO(fernando): what happend with Blockchain forks? if (tx->validation.validated) { ++hits_; continue; @@ -317,8 +343,7 @@ void validate_block::connect_inputs(block_const_ptr block, size_t bucket, size_t } if (stopped()) { - handler(error::service_stopped); - return; + return error::service_stopped; } auto const& prevout = inputs[input_index].previous_output(); @@ -336,7 +361,6 @@ void validate_block::connect_inputs(block_const_ptr block, size_t bucket, size_t #if defined(KTH_CURRENCY_BCH) block_sigchecks += sigchecks; - // if (block_sigchecks > get_max_block_sigchecks(network_)) { if (block_sigchecks > block->validation.state->dynamic_max_block_sigchecks()) { ec = error::block_sigchecks_limit; break; @@ -351,7 +375,7 @@ void validate_block::connect_inputs(block_const_ptr block, size_t bucket, size_t } } - handler(ec); + return ec; } // The tx pool cache hit rate. @@ -360,11 +384,6 @@ float validate_block::hit_rate() const { return queries_ == 0 ? 0.0f : (hits_ * 1.0f / queries_); } -void validate_block::handle_connected(code const& ec, block_const_ptr block, result_handler handler) const { - block->validation.cache_efficiency = hit_rate(); - handler(ec); -} - // Utility. //----------------------------------------------------------------------------- diff --git a/src/blockchain/src/validate/validate_header.cpp b/src/blockchain/src/validate/validate_header.cpp new file mode 100644 index 00000000..2ee02e78 --- /dev/null +++ b/src/blockchain/src/validate/validate_header.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include + +#include +#include + +namespace kth::blockchain { + +using namespace kth::domain::chain; +using namespace kth::infrastructure::config; + +validate_header::validate_header(settings const& settings, domain::config::network network) + : checkpoints_(checkpoint::sort(settings.checkpoints)) + , network_(network) + , retarget_(network != domain::config::network::regtest) +{} + +// Context-free validation +// ----------------------------------------------------------------------------- + +code validate_header::check(domain::chain::header const& header) const { + // Delegate to header's check() which validates: + // 1. Proof of work (hash <= target derived from bits) + // 2. Timestamp not too far in future (2 hours) + return header.check(retarget_); +} + +// Chain-context validation +// ----------------------------------------------------------------------------- + +code validate_header::accept(domain::chain::header const& header, size_t height, + hash_digest const& previous) const { + // Validate chain continuity + if (header.previous_block_hash() != previous) { + return error::store_block_missing_parent; + } + + auto const hash = header.hash(); + + // Validate against checkpoints + if (is_checkpoint_conflict(hash, height)) { + return error::checkpoints_failed; + } + + return error::success; +} + +// Combined validation +// ----------------------------------------------------------------------------- + +code validate_header::validate(domain::chain::header const& header, size_t height, + hash_digest const& previous) const { + // If under checkpoint, we can skip PoW validation (trusted headers) + // This is a significant optimization during IBD + if (!is_under_checkpoint(height)) { + auto const ec = check(header); + if (ec) { + return ec; + } + } + + return accept(header, height, previous); +} + +// Checkpoint helpers +// ----------------------------------------------------------------------------- + +bool validate_header::is_checkpoint_conflict(hash_digest const& hash, size_t height) const { + // Check if there's a checkpoint at this height + auto const it = std::find_if(checkpoints_.begin(), checkpoints_.end(), + [height](checkpoint const& cp) { + return cp.height() == height; + }); + + // If checkpoint exists at this height, hash must match + if (it != checkpoints_.end()) { + if (hash != it->hash()) { + spdlog::warn("[validate_header] Checkpoint conflict at height {}: " + "received hash {} but expected {}", + height, encode_hash(hash), encode_hash(it->hash())); + return true; + } + } + + return false; +} + +bool validate_header::is_under_checkpoint(size_t height) const { + return height <= last_checkpoint_height(); +} + +bool validate_header::is_checkpoint_height(size_t height) const { + return std::any_of(checkpoints_.begin(), checkpoints_.end(), + [height](checkpoint const& cp) { + return cp.height() == height; + }); +} + +std::optional validate_header::checkpoint_hash(size_t height) const { + auto const it = std::find_if(checkpoints_.begin(), checkpoints_.end(), + [height](checkpoint const& cp) { + return cp.height() == height; + }); + + if (it != checkpoints_.end()) { + return it->hash(); + } + + return std::nullopt; +} + +size_t validate_header::last_checkpoint_height() const { + if (checkpoints_.empty()) { + return 0; + } + + // Checkpoints are sorted, so last one has highest height + return checkpoints_.back().height(); +} + +} // namespace kth::blockchain diff --git a/src/blockchain/src/validate/validate_transaction.cpp b/src/blockchain/src/validate/validate_transaction.cpp index 53ca0169..5505203c 100644 --- a/src/blockchain/src/validate/validate_transaction.cpp +++ b/src/blockchain/src/validate/validate_transaction.cpp @@ -11,14 +11,17 @@ #include #include -#include +#include #include #include #include #include #include -#include +#include +#include +#include +#include namespace kth::blockchain { @@ -34,20 +37,21 @@ using namespace std::placeholders; #if defined(KTH_WITH_MEMPOOL) -validate_transaction::validate_transaction(dispatcher& dispatch, fast_chain const& chain, settings const& settings, mining::mempool const& mp) +validate_transaction::validate_transaction(executor_type executor, size_t threads, block_chain const& chain, settings const& settings, mining::mempool const& mp) #else -validate_transaction::validate_transaction(dispatcher& dispatch, fast_chain const& chain, settings const& settings) +validate_transaction::validate_transaction(executor_type executor, size_t threads, block_chain const& chain, settings const& settings) #endif : stopped_(true), retarget_(settings.retarget), - dispatch_(dispatch), + executor_(std::move(executor)), + threads_(threads), #if defined(KTH_WITH_MEMPOOL) - transaction_populator_(dispatch, chain, mp), + transaction_populator_(executor_, threads_, chain, mp), #else - transaction_populator_(dispatch, chain), + transaction_populator_(executor_, threads_, chain), #endif - fast_chain_(chain) + chain_(chain) { } @@ -68,70 +72,84 @@ void validate_transaction::stop() //----------------------------------------------------------------------------- // These checks are context free. -void validate_transaction::check(transaction_const_ptr tx, result_handler handler) const { +::asio::awaitable validate_transaction::check(transaction_const_ptr tx) const { // Run context free checks. - handler(tx->check(true, retarget_)); + co_return tx->check(true, retarget_); } // Accept sequence. //----------------------------------------------------------------------------- // These checks require chain and tx state (net height and enabled forks). -void validate_transaction::accept(transaction_const_ptr tx, result_handler handler) const { +::asio::awaitable validate_transaction::accept(transaction_const_ptr tx) const { // Populate chain state of the next block (tx pool). - tx->validation.state = fast_chain_.chain_state(); + tx->validation.state = chain_.chain_state(); if ( ! tx->validation.state) { - handler(error::transaction_validation_state_failed); - return; + co_return error::transaction_validation_state_failed; } - transaction_populator_.populate(tx, std::bind(&validate_transaction::handle_populated, this, _1, tx, handler)); -} + auto const populate_ec = co_await transaction_populator_.populate(tx); -void validate_transaction::handle_populated(code const& ec, transaction_const_ptr tx, result_handler handler) const { if (stopped()) { - handler(error::service_stopped); - return; + co_return error::service_stopped; } - if (ec) { - handler(ec); - return; + if (populate_ec) { + co_return populate_ec; } KTH_ASSERT(tx->validation.state); // Run contextual tx checks. - handler(tx->accept()); + co_return tx->accept(); } // Connect sequence. //----------------------------------------------------------------------------- // These checks require chain state, block state and perform script validation. -void validate_transaction::connect(transaction_const_ptr tx, result_handler handler) const { +::asio::awaitable validate_transaction::connect(transaction_const_ptr tx) const { KTH_ASSERT(tx->validation.state); auto const total_inputs = tx->inputs().size(); // Return if there are no inputs to validate (will fail later). if (total_inputs == 0) { - handler(error::success); - return; + co_return error::success; } - auto const buckets = std::min(dispatch_.size(), total_inputs); - auto const join_handler = synchronize(handler, buckets, NAME "_validate"); + auto const buckets = std::min(threads_, total_inputs); KTH_ASSERT(buckets != 0); - // If the priority threadpool is shut down when this is called the handler - // will never be invoked, resulting in a threadpool.join indefinite hang. + // Use a channel to collect results from parallel tasks + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor_, buckets); + + // Launch parallel tasks for (size_t bucket = 0; bucket < buckets; ++bucket) { - dispatch_.concurrent(&validate_transaction::connect_inputs, this, tx, bucket, buckets, join_handler); + ::asio::post(executor_, [this, tx, bucket, buckets, channel]() { + auto result = connect_inputs_sync(tx, bucket, buckets); + channel->try_send(std::error_code{}, result); + }); } + + // Wait for all results - return first error or success if all succeed + code final_result = error::success; + for (size_t i = 0; i < buckets; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + // Channel error - shouldn't happen + co_return error::operation_failed; + } + if (result != error::success && final_result == error::success) { + final_result = result; + } + } + + co_return final_result; } -void validate_transaction::connect_inputs(transaction_const_ptr tx, size_t bucket, size_t buckets, result_handler handler) const { +code validate_transaction::connect_inputs_sync(transaction_const_ptr tx, size_t bucket, size_t buckets) const { KTH_ASSERT(bucket < buckets); #if defined(KTH_CURRENCY_BCH) @@ -143,32 +161,28 @@ void validate_transaction::connect_inputs(transaction_const_ptr tx, size_t bucke for (auto input_index = bucket; input_index < inputs.size(); input_index = ceiling_add(input_index, buckets)) { if (stopped()) { - handler(error::service_stopped); - return; + return error::service_stopped; } auto const& prevout = inputs[input_index].previous_output(); if ( ! prevout.validation.cache.is_valid()) { - handler(error::missing_previous_output); - return; + return error::missing_previous_output; } auto res = validate_input::verify_script(*tx, input_index, forks); if (res.first != error::success) { - handler(res.first); - return; + return res.first; } #if defined(KTH_CURRENCY_BCH) tx_sigchecks += res.second; if (tx_sigchecks > max_tx_sigchecks) { - handler(error::transaction_sigchecks_limit); - return; + return error::transaction_sigchecks_limit; } #endif } - handler(error::success); + return error::success; } } // namespace kth::blockchain diff --git a/src/c-api/conanfile.py b/src/c-api/conanfile.py deleted file mode 100644 index 7245e0a3..00000000 --- a/src/c-api/conanfile.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" - -class KnuthCAPIConan(KnuthConanFileV2): - name = "c-api" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/c-api" - description = "Bitcoin Full Node Library with C interface" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = { - "shared": [True, False], - "fPIC": [True, False], - "tests": [True, False], - "console": [True, False], #TODO(fernando): move to kthbuild - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - "no_compilation": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - "verbose": [True, False], - "mempool": [True, False], - "db": ['dynamic'], - "db_readonly": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "tests": True, - "console": False, - "march_strategy": "download_if_possible", - "no_compilation": False, - "currency": "BCH", - "verbose": False, - "mempool": False, - "db": "dynamic", - "db_readonly": False, - "cmake_export_compile_commands": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "knuthbuildinfo.cmake","include/*", "test/*", "console/*" - - def _is_legacy_db(self): - return self.options.db == "legacy" or self.options.db == "legacy_full" - - @property - def is_shared(self): - # if self.settings.compiler == "Visual Studio" and self.msvc_mt_build: - # return False - # else: - # return self.options.shared - return self.options.shared - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def requirements(self): - if not self.options.no_compilation and self.settings.get_safe("compiler") is not None: - self.requires("node/0.58.0", transitive_headers=True, transitive_libs=True) - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - if self.options.no_compilation or (self.settings.compiler == None and self.settings.arch == 'x86_64' and self.settings.os in ('Linux', 'Windows', 'Macos')): - self.settings.remove("compiler") - self.settings.remove("build_type") - - self.options["*"].db_readonly = self.options.db_readonly - self.output.info("Compiling with read-only DB: %s" % (self.options.db_readonly,)) - - self.options["*"].mempool = self.options.mempool - self.output.info("Compiling with mempool: %s" % (self.options.mempool,)) - - - def package_id(self): - KnuthConanFileV2.package_id(self) - - self.info.options.console = "ANY" - self.info.options.no_compilation = "ANY" - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - #TODO(fernando): check and compare "shared" logic with the one in kthbuild - tc.variables["ENABLE_SHARED"] = option_on_off(self.is_shared) - tc.variables["ENABLE_SHARED_CAPI"] = option_on_off(self.is_shared) - # tc.variables["ENABLE_POSITION_INDEPENDENT_CODE"] = option_on_off(self.fPIC_enabled) - - tc.variables["WITH_CONSOLE"] = option_on_off(self.options.console) - tc.variables["WITH_CONSOLE_CAPI"] = option_on_off(self.options.console) - - tc.variables["WITH_MEMPOOL"] = option_on_off(self.options.mempool) - tc.variables["DB_READONLY_MODE"] = option_on_off(self.options.db_readonly) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.verbose = True - cmake.configure() - if not self.options.cmake_export_compile_commands: - cmake.build() - if self.options.tests: - cmake.test() - - # def package(self): - # self.copy("*.h", dst="include", src="include") - # self.copy("*.hpp", dst="include", src="include") - # self.copy("*.ipp", dst="include", src="include") - # self.copy("*.lib", dst="lib", keep_path=False) - # self.copy("*.dll", dst="bin", keep_path=False) - # self.copy("*.dylib*", dst="lib", keep_path=False) - # self.copy("*.so", dst="lib", keep_path=False) - # self.copy("*.a", dst="lib", keep_path=False) - - def package(self): - cmake = CMake(self) - cmake.install() - # rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - # rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) - # rmdir(self, os.path.join(self.package_folder, "res")) - # rmdir(self, os.path.join(self.package_folder, "share")) - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["c-api"] - diff --git a/src/c-api/console/main.cpp b/src/c-api/console/main.cpp index f9aceb7d..ac55855d 100644 --- a/src/c-api/console/main.cpp +++ b/src/c-api/console/main.cpp @@ -415,11 +415,11 @@ int main(int /*argc*/, char* /*argv*/[]) { // int xxx = 0; -// int kth_chain_subscribe_blockchain_handler(kth_node_t exec, kth_chain_t chain, void* ctx, int error, uint64_t fork_height, kth_block_list_t blocks_incoming, kth_block_list_t blocks_replaced) { -// //printf("chain_subscribe_blockchain_handler error: %d\n", error); +// int kth_chain_subscribe_block_handler(kth_node_t exec, kth_chain_t chain, void* ctx, int error, uint64_t fork_height, kth_block_list_t blocks_incoming, kth_block_list_t blocks_replaced) { +// //printf("chain_subscribe_block_handler error: %d\n", error); // if (kth_node_stopped(exec) == 1 || error == 1) { -// printf("chain_subscribe_blockchain_handler -- stopping -- error: %d\n", error); +// printf("chain_subscribe_block_handler -- stopping -- error: %d\n", error); // return 0; // } @@ -483,7 +483,7 @@ int main(int /*argc*/, char* /*argv*/[]) { // printf("**-- 4\n"); -// kth_chain_subscribe_blockchain(exec, chain, nullptr, kth_chain_subscribe_blockchain_handler); +// kth_chain_subscribe_blockchain(exec, chain, nullptr, kth_chain_subscribe_block_handler); // printf("**-- 5\n"); diff --git a/src/c-api/console/print_headers.cpp b/src/c-api/console/print_headers.cpp index 23958996..c74226cc 100644 --- a/src/c-api/console/print_headers.cpp +++ b/src/c-api/console/print_headers.cpp @@ -218,11 +218,11 @@ int main(int /*argc*/, char* /*argv*/[]) { // int xxx = 0; -// int kth_chain_subscribe_blockchain_handler(kth_node_t exec, kth_chain_t chain, void* ctx, int error, uint64_t fork_height, kth_block_list_t blocks_incoming, kth_block_list_t blocks_replaced) { -// //printf("chain_subscribe_blockchain_handler error: %d\n", error); +// int kth_chain_subscribe_block_handler(kth_node_t exec, kth_chain_t chain, void* ctx, int error, uint64_t fork_height, kth_block_list_t blocks_incoming, kth_block_list_t blocks_replaced) { +// //printf("chain_subscribe_block_handler error: %d\n", error); // if (kth_node_stopped(exec) == 1 || error == 1) { -// printf("chain_subscribe_blockchain_handler -- stopping -- error: %d\n", error); +// printf("chain_subscribe_block_handler -- stopping -- error: %d\n", error); // return 0; // } @@ -286,7 +286,7 @@ int main(int /*argc*/, char* /*argv*/[]) { // printf("**-- 4\n"); -// kth_chain_subscribe_blockchain(exec, chain, nullptr, kth_chain_subscribe_blockchain_handler); +// kth_chain_subscribe_blockchain(exec, chain, nullptr, kth_chain_subscribe_block_handler); // printf("**-- 5\n"); diff --git a/src/c-api/include/kth/capi/chain/chain_other.h b/src/c-api/include/kth/capi/chain/chain_other.h index c8206eaa..9306480d 100644 --- a/src/c-api/include/kth/capi/chain/chain_other.h +++ b/src/c-api/include/kth/capi/chain/chain_other.h @@ -15,7 +15,7 @@ extern "C" { #endif KTH_EXPORT -void kth_chain_subscribe_blockchain(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_blockchain_handler_t handler); +void kth_chain_subscribe_blockchain(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_block_handler_t handler); KTH_EXPORT void kth_chain_subscribe_transaction(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_transaction_handler_t handler); @@ -94,6 +94,6 @@ kth_bool_t kth_chain_is_stale(kth_chain_t chain); // Subscribers. //------------------------------------------------------------------------- -//virtual void subscribe_blockchain(reorganize_handler&& handler) = 0; +//virtual void subscribe_blockchain(block_handler&& handler) = 0; //virtual void subscribe_transaction(transaction_handler&& handler) = 0; diff --git a/src/c-api/include/kth/capi/conversions.hpp b/src/c-api/include/kth/capi/conversions.hpp index 625a3c92..d853a1fa 100644 --- a/src/c-api/include/kth/capi/conversions.hpp +++ b/src/c-api/include/kth/capi/conversions.hpp @@ -25,7 +25,7 @@ #include // #ifndef __EMSCRIPTEN__ -#include +#include // #endif KTH_CONV_DECLARE(chain, kth_block_t, kth::domain::chain::block, block) diff --git a/src/c-api/include/kth/capi/primitives.h b/src/c-api/include/kth/capi/primitives.h index 34310fa3..ea51acc9 100644 --- a/src/c-api/include/kth/capi/primitives.h +++ b/src/c-api/include/kth/capi/primitives.h @@ -204,7 +204,7 @@ typedef void (*kth_validate_tx_handler_t)(kth_chain_t, void*, kth_error_code_t, typedef void (*kth_block_locator_fetch_handler_t)(kth_chain_t, void*, kth_error_code_t, kth_get_headers_ptr_t); typedef void (*kth_result_handler_t)(kth_chain_t, void*, kth_error_code_t); typedef void (*kth_transactions_by_address_fetch_handler_t)(kth_chain_t, void*, kth_error_code_t, kth_hash_list_t); -typedef kth_bool_t (*kth_subscribe_blockchain_handler_t)(kth_node_t, kth_chain_t, void*, kth_error_code_t, kth_size_t, kth_block_list_t, kth_block_list_t); +typedef kth_bool_t (*kth_subscribe_block_handler_t)(kth_node_t, kth_chain_t, void*, kth_error_code_t, kth_size_t, kth_block_list_t, kth_block_list_t); typedef kth_bool_t (*kth_subscribe_transaction_handler_t)(kth_node_t, kth_chain_t, void*, kth_error_code_t, kth_transaction_t); typedef kth_bool_t (*kth_subscribe_ds_proof_handler_t)(kth_node_t, kth_chain_t, void*, kth_error_code_t, kth_double_spend_proof_t); diff --git a/src/c-api/src/chain/chain_async.cpp b/src/c-api/src/chain/chain_async.cpp index 28ee3090..3f9636b0 100644 --- a/src/c-api/src/chain/chain_async.cpp +++ b/src/c-api/src/chain/chain_async.cpp @@ -13,17 +13,20 @@ #include #include #include -#include +#include #include #include #include +#include +#include + namespace { inline -kth::blockchain::safe_chain& safe_chain(kth_chain_t chain) { - return *static_cast(chain); +kth::blockchain::block_chain& safe_chain(kth_chain_t chain) { + return *static_cast(chain); } inline @@ -186,15 +189,21 @@ void kth_chain_async_confirmed_transactions(kth_chain_t chain, void* ctx, kth_pa //------------------------------------------------------------------------- void kth_chain_async_organize_block(kth_chain_t chain, void* ctx, kth_block_t block, kth_result_handler_t handler) { - safe_chain(chain).organize(block_shared(block), [chain, ctx, handler](std::error_code const& ec) { + auto& bc = safe_chain(chain); + auto block_cpp = block_shared(block); + ::asio::co_spawn(bc.executor(), [&bc, block_cpp, chain, ctx, handler]() -> ::asio::awaitable { + auto ec = co_await bc.organize(block_cpp); handler(chain, ctx, kth::to_c_err(ec)); - }); + }, ::asio::detached); } void kth_chain_async_organize_transaction(kth_chain_t chain, void* ctx, kth_transaction_t transaction, kth_result_handler_t handler) { - safe_chain(chain).organize(tx_shared(transaction), [chain, ctx, handler](std::error_code const& ec) { + auto& bc = safe_chain(chain); + auto tx_cpp = tx_shared(transaction); + ::asio::co_spawn(bc.executor(), [&bc, tx_cpp, chain, ctx, handler]() -> ::asio::awaitable { + auto ec = co_await bc.organize(tx_cpp); handler(chain, ctx, kth::to_c_err(ec)); - }); + }, ::asio::detached); } } // extern "C" diff --git a/src/c-api/src/chain/chain_other.cpp b/src/c-api/src/chain/chain_other.cpp index aa27bc42..74cd9d22 100644 --- a/src/c-api/src/chain/chain_other.cpp +++ b/src/c-api/src/chain/chain_other.cpp @@ -13,17 +13,21 @@ #include #include #include -#include +#include #include #include #include +#include +#include +#include + namespace { inline -kth::blockchain::safe_chain& safe_chain(kth_chain_t chain) { - return *static_cast(chain); +kth::blockchain::block_chain& safe_chain(kth_chain_t chain) { + return *static_cast(chain); } inline @@ -61,53 +65,118 @@ extern "C" { // Subscribers. //------------------------------------------------------------------------- -void kth_chain_subscribe_blockchain(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_blockchain_handler_t handler) { - safe_chain(chain).subscribe_blockchain([exec, chain, ctx, handler](std::error_code const& ec, size_t fork_height, kth::block_const_ptr_list_const_ptr incoming, kth::block_const_ptr_list_const_ptr replaced_blocks) { +void kth_chain_subscribe_blockchain(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_block_handler_t handler) { + auto& bc = safe_chain(chain); + auto channel = bc.subscribe_blockchain(); + + if ( ! channel) { + // Broadcaster is stopped + handler(exec, chain, ctx, kth::to_c_err(kth::error::service_stopped), 0, nullptr, nullptr); + return; + } + + ::asio::co_spawn(bc.executor(), [exec, chain, ctx, handler, channel, &bc]() -> ::asio::awaitable { + while (channel->is_open()) { + auto result = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + auto& [ec, fork_height, incoming, replaced_blocks] = result; + + if (ec) { + // Channel closed or error + handler(exec, chain, ctx, kth::to_c_err(kth::error::service_stopped), 0, nullptr, nullptr); + break; + } - if (safe_chain(chain).is_stale()) { // TODO(fernando): Move somewhere else (there should be no logic here) - return 1; - } + if (bc.is_stale()) { + continue; + } - kth_block_list_t incoming_cpp = nullptr; - if (incoming) { - incoming_cpp = kth_chain_block_list_construct_default(); - for (auto&& x : *incoming) { - // auto new_block = new kth::domain::chain::block(*x); - // kth_chain_block_list_push_back(incoming_cpp, new_block); - kth_chain_block_list_push_back(incoming_cpp, cast_block(*x)); + kth_block_list_t incoming_cpp = nullptr; + if (incoming) { + incoming_cpp = kth_chain_block_list_construct_default(); + for (auto&& x : *incoming) { + kth_chain_block_list_push_back(incoming_cpp, cast_block(*x)); + } } - } - kth_block_list_t replaced_blocks_cpp = nullptr; - if (replaced_blocks) { - replaced_blocks_cpp = kth_chain_block_list_construct_default(); - for (auto&& x : *replaced_blocks) { - // auto new_block = new kth::domain::chain::block(*x); - // kth_chain_block_list_push_back(replaced_blocks_cpp, new_block); - // kth_chain_block_list_push_back_const(replaced_blocks_cpp, x.get()); - kth_chain_block_list_push_back(replaced_blocks_cpp, cast_block(*x)); + kth_block_list_t replaced_blocks_cpp = nullptr; + if (replaced_blocks) { + replaced_blocks_cpp = kth_chain_block_list_construct_default(); + for (auto&& x : *replaced_blocks) { + kth_chain_block_list_push_back(replaced_blocks_cpp, cast_block(*x)); + } } - } - auto res = handler(exec, chain, ctx, kth::to_c_err(ec), fork_height, incoming_cpp, replaced_blocks_cpp); - return res; - }); + auto res = handler(exec, chain, ctx, kth::to_c_err(std::error_code{}), fork_height, incoming_cpp, replaced_blocks_cpp); + if (res == 0) { + // Unsubscribe requested + bc.unsubscribe_blockchain(channel); + break; + } + } + }, ::asio::detached); } void kth_chain_subscribe_transaction(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_transaction_handler_t handler) { - safe_chain(chain).subscribe_transaction([exec, chain, ctx, handler](std::error_code const& ec, kth::transaction_const_ptr tx) { - return handler(exec, chain, ctx, kth::to_c_err(ec), kth::leak_if_success(tx, ec)); - }); + auto& bc = safe_chain(chain); + auto channel = bc.subscribe_transaction(); + + if ( ! channel) { + handler(exec, chain, ctx, kth::to_c_err(kth::error::service_stopped), nullptr); + return; + } + + ::asio::co_spawn(bc.executor(), [exec, chain, ctx, handler, channel, &bc]() -> ::asio::awaitable { + while (channel->is_open()) { + auto result = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + auto& [ec, tx] = result; + + if (ec) { + handler(exec, chain, ctx, kth::to_c_err(kth::error::service_stopped), nullptr); + break; + } + + auto res = handler(exec, chain, ctx, kth::to_c_err(std::error_code{}), kth::leak(tx)); + if (res == 0) { + bc.unsubscribe_transaction(channel); + break; + } + } + }, ::asio::detached); } void kth_chain_subscribe_ds_proof(kth_node_t exec, kth_chain_t chain, void* ctx, kth_subscribe_ds_proof_handler_t handler) { - safe_chain(chain).subscribe_ds_proof([exec, chain, ctx, handler](std::error_code const& ec, kth::double_spend_proof_const_ptr dsp) { - return handler(exec, chain, ctx, kth::to_c_err(ec), kth::leak_if_success(dsp, ec)); - }); + auto& bc = safe_chain(chain); + auto channel = bc.subscribe_ds_proof(); + + if ( ! channel) { + handler(exec, chain, ctx, kth::to_c_err(kth::error::service_stopped), nullptr); + return; + } + + ::asio::co_spawn(bc.executor(), [exec, chain, ctx, handler, channel, &bc]() -> ::asio::awaitable { + while (channel->is_open()) { + auto result = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + auto& [ec, dsp] = result; + + if (ec) { + handler(exec, chain, ctx, kth::to_c_err(kth::error::service_stopped), nullptr); + break; + } + + auto res = handler(exec, chain, ctx, kth::to_c_err(std::error_code{}), kth::leak(dsp)); + if (res == 0) { + bc.unsubscribe_ds_proof(channel); + break; + } + } + }, ::asio::detached); } -void kth_chain_unsubscribe(kth_chain_t chain) { - safe_chain(chain).unsubscribe(); +// Note: kth_chain_unsubscribe is no longer needed with the new model +// Each subscription manages its own lifecycle via the returned channel +void kth_chain_unsubscribe(kth_chain_t /*chain*/) { + // No-op: subscriptions are now managed individually + // Callers should return 0 from their handler to unsubscribe } void kth_chain_transaction_validate_sequential(kth_chain_t chain, void* ctx, kth_transaction_t tx, kth_validate_tx_handler_t handler) { @@ -116,25 +185,30 @@ void kth_chain_transaction_validate_sequential(kth_chain_t chain, void* ctx, kth auto tx_cpp = tx_shared(tx); tx_cpp->validation.simulate = true; - safe_chain(chain).organize(tx_cpp, [chain, ctx, handler](std::error_code const& ec) { + auto& bc = safe_chain(chain); + ::asio::co_spawn(bc.executor(), [&bc, tx_cpp, chain, ctx, handler]() -> ::asio::awaitable { + auto ec = co_await bc.organize(tx_cpp); if (ec) { handler(chain, ctx, kth::to_c_err(ec), ec.message().c_str()); } else { handler(chain, ctx, kth::to_c_err(ec), nullptr); } - }); + }, ::asio::detached); } void kth_chain_transaction_validate(kth_chain_t chain, void* ctx, kth_transaction_t tx, kth_validate_tx_handler_t handler) { if (handler == nullptr) return; - safe_chain(chain).transaction_validate(tx_shared(tx), [chain, ctx, handler](std::error_code const& ec) { + auto& bc = safe_chain(chain); + auto tx_cpp = tx_shared(tx); + ::asio::co_spawn(bc.executor(), [&bc, tx_cpp, chain, ctx, handler]() -> ::asio::awaitable { + auto ec = co_await bc.transaction_validate(tx_cpp); if (ec) { handler(chain, ctx, kth::to_c_err(ec), ec.message().c_str()); } else { handler(chain, ctx, kth::to_c_err(ec), nullptr); } - }); + }, ::asio::detached); } // Properties. diff --git a/src/c-api/src/chain/chain_sync.cpp b/src/c-api/src/chain/chain_sync.cpp index 47ccfb82..158fbeee 100644 --- a/src/c-api/src/chain/chain_sync.cpp +++ b/src/c-api/src/chain/chain_sync.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -23,8 +23,8 @@ namespace { inline -kth::blockchain::safe_chain& safe_chain(kth_chain_t chain) { - return *static_cast(chain); +kth::blockchain::block_chain& safe_chain(kth_chain_t chain) { + return *static_cast(chain); } inline diff --git a/src/c-api/src/chain/mempool_transaction.cpp b/src/c-api/src/chain/mempool_transaction.cpp index ff8e48d7..316b1fb3 100644 --- a/src/c-api/src/chain/mempool_transaction.cpp +++ b/src/c-api/src/chain/mempool_transaction.cpp @@ -6,7 +6,7 @@ #include -#include +#include #include #include diff --git a/src/c-api/src/chain/mempool_transaction_list.cpp b/src/c-api/src/chain/mempool_transaction_list.cpp index 5907bc3d..50afa16b 100644 --- a/src/c-api/src/chain/mempool_transaction_list.cpp +++ b/src/c-api/src/chain/mempool_transaction_list.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include diff --git a/src/c-api/src/node.cpp b/src/c-api/src/node.cpp index 4c6fe3e9..0d5dca0c 100644 --- a/src/c-api/src/node.cpp +++ b/src/c-api/src/node.cpp @@ -109,7 +109,7 @@ kth_chain_t kth_node_get_chain(kth_node_t node) { kth_p2p_t kth_node_get_p2p(kth_node_t node) { #if ! defined(__EMSCRIPTEN__) - return &static_cast(kth_node_cpp(node).node()); + return &kth_node_cpp(node).node().network(); #else return nullptr; #endif diff --git a/src/consensus/conanfile.py b/src/consensus/conanfile.py deleted file mode 100644 index 37feeeb0..00000000 --- a/src/consensus/conanfile.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy #, apply_conandata_patches, export_conandata_patches, get, rm, rmdir -from kthbuild import option_on_off, march_conan_manip, pass_march_to_compiler -from kthbuild import KnuthConanFileV2 - -required_conan_version = ">=2.0" - -class KnuthConsensusConan(KnuthConanFileV2): - name = "consensus" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/consensus" - description = "Bitcoin Consensus Library" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = {"shared": [True, False], - "fPIC": [True, False], - "tests": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - "verbose": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "tests": True, - "currency": "BCH", - "march_strategy": "download_if_possible", - "verbose": False, - "cmake_export_compile_commands": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "knuthbuildinfo.cmake", "include/*", "test/*" - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.7.1") - - def requirements(self): - self.requires("boost/1.89.0", transitive_headers=True, transitive_libs=True) - self.requires("openssl/3.4.1", transitive_headers=True, transitive_libs=True) - self.requires("secp256k1/0.22.0", transitive_headers=True, transitive_libs=True) - - if self.settings.compiler == "msvc" and self.options.currency == 'BCH': - self.requires("safeint/3.0.28", transitive_headers=True, transitive_libs=True) - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - # "enable_experimental=False", \ - # "enable_endomorphism=False", \ - # "enable_ecmult_static_precomputation=True", \ - # "enable_module_ecdh=False", \ - # "enable_module_schnorr=True", \ - # "enable_module_recovery=True", \ - # "enable_module_multiset=True", \ - - # if self.options.log != "boost": - # self.options["boost"].without_filesystem = True - # self.options["boost"].without_log = True - - if self.settings.os == "Emscripten": - self.options["boost/*"].header_only = True - - if self.options.currency == 'BCH': - self.options["secp256k1/*"].enable_module_schnorr = True - else: - self.options["secp256k1/*"].enable_module_schnorr = False - - def package_id(self): - KnuthConanFileV2.package_id(self) - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - # tc.variables["ENABLE_TEST"] = option_on_off(self.options.with_tests) - # tc.variables["WITH_JAVA"] = option_on_off(self.options.with_java) - # tc.variables["WITH_PYTHON"] = option_on_off(self.options.with_python) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - - if not self.options.cmake_export_compile_commands: - cmake.build() - if self.options.tests: - cmake.test() - # cmake.test(target="tests") - - # def imports(self): - # self.copy("*.h", "", "include") - - def package(self): - cmake = CMake(self) - cmake.install() - # rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - # rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) - # rmdir(self, os.path.join(self.package_folder, "res")) - # rmdir(self, os.path.join(self.package_folder, "share")) - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["consensus"] diff --git a/src/database/conanfile.py b/src/database/conanfile.py deleted file mode 100644 index 1d1cc804..00000000 --- a/src/database/conanfile.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy #, apply_conandata_patches, export_conandata_patches, get, rm, rmdir -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" - -class KnuthDatabaseConan(KnuthConanFileV2): - name = "database" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/database/tree/conan-build/conanfile.py" - description = "High Performance Blockchain Database" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = {"shared": [True, False], - "fPIC": [True, False], - "tests": [True, False], - "tools": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - "verbose": [True, False], - "measurements": [True, False], - "db": ['dynamic'], - "db_readonly": [True, False], - "cached_rpc_data": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "tests": True, - "tools": False, - "currency": "BCH", - "march_strategy": "download_if_possible", - "verbose": False, - "measurements": False, - "db": "dynamic", - "db_readonly": False, - "cached_rpc_data": False, - "cmake_export_compile_commands": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "knuthbuildinfo.cmake", "include/*", "test/*", "tools/*" - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def requirements(self): - self.requires("domain/0.45.0", transitive_headers=True, transitive_libs=True) - self.requires("lmdb/0.9.32", transitive_headers=True, transitive_libs=True) - self.output.info("Using lmdb for DB management") - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - self.options["*"].cached_rpc_data = self.options.cached_rpc_data - self.options["*"].measurements = self.options.measurements - - self.options["*"].db_readonly = self.options.db_readonly - self.output.info("Compiling with read-only DB: %s" % (self.options.db_readonly,)) - - # self.options["*"].currency = self.options.currency - # self.output.info("Compiling for currency: %s" % (self.options.currency,)) - self.output.info("Compiling with measurements: %s" % (self.options.measurements,)) - self.output.info("Compiling for DB: %s" % (self.options.db,)) - - - def package_id(self): - KnuthConanFileV2.package_id(self) - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - tc.variables["WITH_MEASUREMENTS"] = option_on_off(self.options.measurements) - tc.variables["DB_READONLY_MODE"] = option_on_off(self.options.db_readonly) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - - if self.options.cmake_export_compile_commands: - tc.variables["CMAKE_EXPORT_COMPILE_COMMANDS"] = option_on_off(self.options.cmake_export_compile_commands) - - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - - if not self.options.cmake_export_compile_commands: - cmake.build() - #Note: Cmake Tests and Visual Studio doesn't work - if self.options.tests: - cmake.test() - # cmake.test(target="tests") - - # def imports(self): - # self.copy("*.h", "", "include") - - def package(self): - cmake = CMake(self) - cmake.install() - # rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - # rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) - # rmdir(self, os.path.join(self.package_folder, "res")) - # rmdir(self, os.path.join(self.package_folder, "share")) - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["database"] - diff --git a/src/database/include/kth/database/data_base.hpp b/src/database/include/kth/database/data_base.hpp index fa5952ae..99e17a5b 100644 --- a/src/database/include/kth/database/data_base.hpp +++ b/src/database/include/kth/database/data_base.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -19,15 +20,19 @@ #include #include -#include + +#include +#include namespace kth::database { +using kth::awaitable_expected; + /// This class is thread safe and implements the sequential locking pattern. struct KD_API data_base : store, noncopyable { public: + using executor_type = ::asio::any_io_executor; using handle = store::handle; - using result_handler = handle0; using path = kth::path; // Construct. @@ -75,15 +80,32 @@ struct KD_API data_base : store, noncopyable { /// Returns store_block_invalid_height if height is not the current top + 1. code push(domain::chain::block const& block, size_t height); + /// Push a header for headers-first sync (without full block data). + /// Returns store_block_invalid_height if height is not the current top + 1. + code push_header(domain::chain::header const& header, size_t height); + + /// Push a header with explicit ABLA state for headers-first sync. + /// Returns store_block_invalid_height if height is not the current top + 1. + code push_header(domain::chain::header const& header, size_t height, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size); + + /// Push multiple headers in a single transaction (batch). + /// start_height is the height of the first header in the list. + code push_headers_batch(domain::chain::header::list const& headers, size_t start_height); + code prune_reorg(); //bool set_database_flags(bool fast); - // Asynchronous writers. + // Coroutine writers. // ------------------------------------------------------------------------ - /// Invoke pop_all and then push_all under a common lock. - void reorganize(infrastructure::config::checkpoint const& fork_point, block_const_ptr_list_const_ptr incoming_blocks, block_const_ptr_list_ptr outgoing_blocks, dispatcher& dispatch, result_handler handler); + /// Invoke pop_above and then push_all. + /// Returns the outgoing blocks that were popped. + [[nodiscard]] + awaitable_expected reorganize( + executor_type executor, + infrastructure::config::checkpoint const& fork_point, + block_const_ptr_list_const_ptr incoming_blocks); #endif // ! defined(KTH_DB_READONLY) protected: @@ -91,15 +113,17 @@ struct KD_API data_base : store, noncopyable { #if ! defined(KTH_DB_READONLY) - // Sets error if first_height is not the current top + 1 or not linked. - void push_all(block_const_ptr_list_const_ptr in_blocks, size_t first_height, dispatcher& dispatch, result_handler handler); + // Push all blocks starting at first_height. + // Selects parallel or sequential based on settings_.parallel_block_push. + [[nodiscard]] + ::asio::awaitable push_all(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height); // Pop the set of blocks above the given hash. - // Sets error if the database is corrupt or the hash doesn't exist. - // Any blocks returned were successfully popped prior to any failure. - void pop_above(block_const_ptr_list_ptr out_blocks, hash_digest const& fork_hash, dispatcher& dispatch, result_handler handler); -#endif // ! defined(KTH_DB_READONLY) + // Returns the popped blocks or an error if the database is corrupt or the hash doesn't exist. + [[nodiscard]] + awaitable_expected pop_above(executor_type executor, hash_digest const& fork_hash); +#endif // ! defined(KTH_DB_READONLY) std::shared_ptr internal_db_; @@ -110,28 +134,27 @@ struct KD_API data_base : store, noncopyable { #if ! defined(KTH_DB_READONLY) code push_genesis(domain::chain::block const& block); - // Synchronous writers. + // Synchronous helpers. // ------------------------------------------------------------------------ bool pop(domain::chain::block& out_block); - bool pop_inputs(const inputs& inputs, size_t height); - bool pop_outputs(const outputs& outputs, size_t height); + bool pop_inputs(inputs const& inputs, size_t height); + bool pop_outputs(outputs const& outputs, size_t height); + + // Push a single block to the database (synchronous, called from coroutine). + code do_push(block_const_ptr block, size_t height, uint32_t median_time_past); + + // Push all blocks sequentially (one after another). + [[nodiscard]] + ::asio::awaitable push_all_sequential(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height); + // Push all blocks in parallel (dispatch all, collect results). + [[nodiscard]] + ::asio::awaitable push_all_parallel(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height); #endif // ! defined(KTH_DB_READONLY) code verify_insert(domain::chain::block const& block, size_t height); code verify_push(domain::chain::block const& block, size_t height) const; - // Asynchronous writers. - // ------------------------------------------------------------------------ -#if ! defined(KTH_DB_READONLY) - void push_next(code const& ec, block_const_ptr_list_const_ptr blocks, size_t index, size_t height, dispatcher& dispatch, result_handler handler); - void do_push(block_const_ptr block, size_t height, uint32_t median_time_past, dispatcher& dispatch, result_handler handler); - - - void handle_pop(code const& ec, block_const_ptr_list_const_ptr incoming_blocks, size_t first_height, dispatcher& dispatch, result_handler handler); - void handle_push(code const& ec, result_handler handler) const; -#endif // ! defined(KTH_DB_READONLY) - std::atomic closed_; settings const& settings_; }; diff --git a/src/database/include/kth/database/databases/block_database.ipp b/src/database/include/kth/database/databases/block_database.ipp index 84ca9413..1fc1ee8d 100644 --- a/src/database/include/kth/database/databases/block_database.ipp +++ b/src/database/include/kth/database/databases/block_database.ipp @@ -11,68 +11,76 @@ namespace kth::database { //public template -std::pair internal_database_basis::get_block(hash_digest const& hash) const { +std::expected, result_code> internal_database_basis::get_block(hash_digest const& hash) const { auto key = kth_db_make_value(hash.size(), const_cast(hash).data()); KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } KTH_DB_val value; - if (kth_db_get(db_txn, dbi_block_header_by_hash_, &key, &value) != KTH_DB_SUCCESS) { + auto res0 = kth_db_get(db_txn, dbi_block_header_by_hash_, &key, &value); + if (res0 == KTH_DB_NOTFOUND) { kth_db_txn_commit(db_txn); - // kth_db_txn_abort(db_txn); - return {}; + return std::unexpected(result_code::key_not_found); + } + if (res0 != KTH_DB_SUCCESS) { + kth_db_txn_commit(db_txn); + return std::unexpected(result_code::other); } // assert kth_db_get_size(value) == 4; auto height = *static_cast(kth_db_get_data(value)); - auto block = get_block(height, db_txn); + auto block_result = get_block(height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); + } + + if ( ! block_result) { + return std::unexpected(block_result.error()); } - return {block, height}; + return std::make_pair(*block_result, height); } //public template -domain::chain::block internal_database_basis::get_block(uint32_t height) const { +std::expected internal_database_basis::get_block(uint32_t height) const { KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return domain::chain::block{}; + return std::unexpected(result_code::other); } - auto block = get_block(height, db_txn); + auto result = get_block(height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return domain::chain::block{}; + return std::unexpected(result_code::other); } - return block; + return result; } template -domain::chain::block internal_database_basis::get_block(uint32_t height, KTH_DB_txn* db_txn) const { +std::expected internal_database_basis::get_block(uint32_t height, KTH_DB_txn* db_txn) const { auto key = kth_db_make_value(sizeof(height), &height); if (db_mode_ == db_mode_type::full) { - auto header = get_header(height, db_txn); - if ( ! header.is_valid()) { - return {}; + auto header_result = get_header(height, db_txn); + if ( ! header_result) { + return std::unexpected(header_result.error()); } domain::chain::transaction::list tx_list; KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_block_db_, &cursor) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } KTH_DB_val value; @@ -83,7 +91,8 @@ domain::chain::block internal_database_basis::get_block(uint32_t height, auto const entry = get_transaction(tx_id, db_txn); if ( ! entry.is_valid()) { - return {}; + kth_db_cursor_close(cursor); + return std::unexpected(result_code::other); } tx_list.push_back(std::move(entry.transaction())); @@ -97,26 +106,29 @@ domain::chain::block internal_database_basis::get_block(uint32_t height, kth_db_cursor_close(cursor); - return domain::chain::block{header, std::move(tx_list)}; + return domain::chain::block{*header_result, std::move(tx_list)}; } else if (db_mode_ == db_mode_type::blocks) { KTH_DB_val value; - if (kth_db_get(db_txn, dbi_block_db_, &key, &value) != KTH_DB_SUCCESS) { - return domain::chain::block{}; + auto res0 = kth_db_get(db_txn, dbi_block_db_, &key, &value); + if (res0 == KTH_DB_NOTFOUND) { + return std::unexpected(result_code::key_not_found); + } + if (res0 != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); byte_reader reader(data); auto res = domain::chain::block::from_data(reader); if ( ! res) { - return domain::chain::block{}; + return std::unexpected(result_code::other); } return *res; } // db_mode_ == db_mode_type::pruned { - auto block = get_block_reorg(height, db_txn); - return block; + return get_block_reorg(height, db_txn); } diff --git a/src/database/include/kth/database/databases/header_abla_entry.hpp b/src/database/include/kth/database/databases/header_abla_entry.hpp index b7a675a0..1ac4e0fe 100644 --- a/src/database/include/kth/database/databases/header_abla_entry.hpp +++ b/src/database/include/kth/database/databases/header_abla_entry.hpp @@ -15,6 +15,12 @@ using header_with_abla_state_t = std::tuple void to_data_with_abla_state(W& sink, domain::chain::block const& block) { block.header().to_data(sink, true); @@ -30,6 +36,26 @@ void to_data_with_abla_state(W& sink, domain::chain::block const& block) { } } +// Header-only serialization (without ABLA state - for headers-first sync) +template +void to_data_header_only(W& sink, domain::chain::header const& header) { + header.to_data(sink, true); + // ABLA state is unknown for headers received before blocks + // Store zeros, will be updated when block is received + sink.write_8_bytes_little_endian(0); + sink.write_8_bytes_little_endian(0); + sink.write_8_bytes_little_endian(0); +} + +// Header serialization with explicit ABLA state (for headers-first sync with ABLA propagation) +template +void to_data_header_with_abla_state(W& sink, domain::chain::header const& header, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size) { + header.to_data(sink, true); + sink.write_8_bytes_little_endian(block_size); + sink.write_8_bytes_little_endian(control_block_size); + sink.write_8_bytes_little_endian(elastic_buffer_size); +} + expect get_header_and_abla_state_from_data(byte_reader& reader); diff --git a/src/database/include/kth/database/databases/header_database.ipp b/src/database/include/kth/database/databases/header_database.ipp index 006c660f..70c5d51d 100644 --- a/src/database/include/kth/database/databases/header_database.ipp +++ b/src/database/include/kth/database/databases/header_database.ipp @@ -45,40 +45,211 @@ result_code internal_database_basis::push_block_header(domain::chain::blo return result_code::success; } + +template +result_code internal_database_basis::push_header_only(domain::chain::header const& header, uint32_t height, KTH_DB_txn* db_txn) { + + auto valuearr = to_data_header_only(header); + auto key = kth_db_make_value(sizeof(height), &height); + auto value = kth_db_make_value(valuearr.size(), valuearr.data()); + + auto res = kth_db_put(db_txn, dbi_block_header_, &key, &value, KTH_DB_APPEND); + if (res == KTH_DB_KEYEXIST) { + spdlog::info("[database] Duplicate key inserting header [push_header_only] {}", res); + return result_code::duplicated_key; + } + if (res != KTH_DB_SUCCESS) { + spdlog::info("[database] Error inserting header [push_header_only] {}", res); + return result_code::other; + } + + auto key_by_hash_arr = header.hash(); + auto key_by_hash = kth_db_make_value(key_by_hash_arr.size(), key_by_hash_arr.data()); + + res = kth_db_put(db_txn, dbi_block_header_by_hash_, &key_by_hash, &key, KTH_DB_NOOVERWRITE); + if (res == KTH_DB_KEYEXIST) { + spdlog::info("[database] Duplicate key inserting header by hash [push_header_only] {}", res); + return result_code::duplicated_key; + } + if (res != KTH_DB_SUCCESS) { + spdlog::info("[database] Error inserting header by hash [push_header_only] {}", res); + return result_code::other; + } + + return result_code::success; +} + +template +result_code internal_database_basis::push_header(domain::chain::header const& header, uint32_t height) { + KTH_DB_txn* db_txn; + auto res = kth_db_txn_begin(env_, NULL, 0, &db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + auto result = push_header_only(header, height, db_txn); + if (result != result_code::success) { + kth_db_txn_abort(db_txn); + return result; + } + + // Update last_header_height property + result = set_property_height(property_code::last_header_height, height, db_txn); + if (result != result_code::success) { + kth_db_txn_abort(db_txn); + return result; + } + + res = kth_db_txn_commit(db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + return result_code::success; +} + +template +result_code internal_database_basis::push_header_with_abla(domain::chain::header const& header, uint32_t height, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size, KTH_DB_txn* db_txn) { + + auto valuearr = to_data_header_with_abla_state(header, block_size, control_block_size, elastic_buffer_size); + auto key = kth_db_make_value(sizeof(height), &height); + auto value = kth_db_make_value(valuearr.size(), valuearr.data()); + + auto res = kth_db_put(db_txn, dbi_block_header_, &key, &value, KTH_DB_APPEND); + if (res == KTH_DB_KEYEXIST) { + spdlog::info("[database] Duplicate key inserting header [push_header_with_abla] {}", res); + return result_code::duplicated_key; + } + if (res != KTH_DB_SUCCESS) { + spdlog::info("[database] Error inserting header [push_header_with_abla] {}", res); + return result_code::other; + } + + auto key_by_hash_arr = header.hash(); + auto key_by_hash = kth_db_make_value(key_by_hash_arr.size(), key_by_hash_arr.data()); + + res = kth_db_put(db_txn, dbi_block_header_by_hash_, &key_by_hash, &key, KTH_DB_NOOVERWRITE); + if (res == KTH_DB_KEYEXIST) { + spdlog::info("[database] Duplicate key inserting header by hash [push_header_with_abla] {}", res); + return result_code::duplicated_key; + } + if (res != KTH_DB_SUCCESS) { + spdlog::info("[database] Error inserting header by hash [push_header_with_abla] {}", res); + return result_code::other; + } + + return result_code::success; +} + +template +result_code internal_database_basis::push_header(domain::chain::header const& header, uint32_t height, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size) { + KTH_DB_txn* db_txn; + auto res = kth_db_txn_begin(env_, NULL, 0, &db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + auto result = push_header_with_abla(header, height, block_size, control_block_size, elastic_buffer_size, db_txn); + if (result != result_code::success) { + kth_db_txn_abort(db_txn); + return result; + } + + // Update last_header_height property + result = set_property_height(property_code::last_header_height, height, db_txn); + if (result != result_code::success) { + kth_db_txn_abort(db_txn); + return result; + } + + res = kth_db_txn_commit(db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + return result_code::success; +} + +template +result_code internal_database_basis::push_headers_batch(domain::chain::header::list const& headers, uint32_t start_height) { + if (headers.empty()) { + return result_code::success; + } + + KTH_DB_txn* db_txn; + auto res = kth_db_txn_begin(env_, NULL, 0, &db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + uint32_t height = start_height; + for (auto const& header : headers) { + auto result = push_header_only(header, height, db_txn); + if (result != result_code::success && result != result_code::duplicated_key) { + kth_db_txn_abort(db_txn); + return result; + } + ++height; + } + + // Update last_header_height property to the last height + auto const final_height = start_height + static_cast(headers.size()) - 1; + auto result = set_property_height(property_code::last_header_height, final_height, db_txn); + if (result != result_code::success) { + kth_db_txn_abort(db_txn); + return result; + } + + res = kth_db_txn_commit(db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + return result_code::success; +} + #endif // ! defined(KTH_DB_READONLY) template -domain::chain::header internal_database_basis::get_header(uint32_t height, KTH_DB_txn* db_txn) const { +std::expected internal_database_basis::get_header(uint32_t height, KTH_DB_txn* db_txn) const { auto key = kth_db_make_value(sizeof(height), &height); KTH_DB_val value; - if (kth_db_get(db_txn, dbi_block_header_, &key, &value) != KTH_DB_SUCCESS) { - return {}; + auto res = kth_db_get(db_txn, dbi_block_header_, &key, &value); + if (res == KTH_DB_NOTFOUND) { + return std::unexpected(result_code::key_not_found); + } + if (res != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); byte_reader reader(data); auto opt = get_header_and_abla_state_from_data(reader); if ( ! opt) { - return {}; + return std::unexpected(result_code::other); } return std::get<0>(*opt); } template -std::optional internal_database_basis::get_header_and_abla_state(uint32_t height, KTH_DB_txn* db_txn) const { +std::expected internal_database_basis::get_header_and_abla_state(uint32_t height, KTH_DB_txn* db_txn) const { auto key = kth_db_make_value(sizeof(height), &height); KTH_DB_val value; - if (kth_db_get(db_txn, dbi_block_header_, &key, &value) != KTH_DB_SUCCESS) { - return {}; + auto res = kth_db_get(db_txn, dbi_block_header_, &key, &value); + if (res == KTH_DB_NOTFOUND) { + return std::unexpected(result_code::key_not_found); + } + if (res != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); byte_reader reader(data); auto opt = get_header_and_abla_state_from_data(reader); if ( ! opt) { - return {}; + return std::unexpected(result_code::other); } return *opt; } diff --git a/src/database/include/kth/database/databases/history_database.ipp b/src/database/include/kth/database/databases/history_database.ipp index 4b96df27..7fb11b29 100644 --- a/src/database/include/kth/database/databases/history_database.ipp +++ b/src/database/include/kth/database/databases/history_database.ipp @@ -66,7 +66,7 @@ result_code internal_database_basis::insert_input_history(domain::chain:: //auto entry = get_transaction(prevout.hash(), max_uint32, true, db_txn); - if (entry.is_valid()) { + if (entry) { //auto const& tx = entry.transaction(); @@ -80,7 +80,7 @@ result_code internal_database_basis::insert_input_history(domain::chain:: uint64_t id = history_count; - auto const& out_output = entry.output(); + auto const& out_output = entry->output(); for (auto const& address : out_output.addresses()) { auto valuearr = history_entry::factory_to_data(id, inpoint, domain::chain::point_kind::spend, height, inpoint.index(), prevout.checksum()); auto res = insert_history_db(address, valuearr, db_txn); @@ -89,8 +89,7 @@ result_code internal_database_basis::insert_input_history(domain::chain:: } ++id; } - } - else { + } else { spdlog::info("[database] Error finding UTXO for input history [insert_input_history]"); } } @@ -135,7 +134,7 @@ domain::chain::history_compact internal_database_basis::history_entry_to_ } template -domain::chain::history_compact::list internal_database_basis::get_history(short_hash const& key, size_t limit, size_t from_height) const { +std::expected internal_database_basis::get_history(short_hash const& key, size_t limit, size_t from_height) const { domain::chain::history_compact::list result; @@ -146,13 +145,13 @@ domain::chain::history_compact::list internal_database_basis::get_history KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return result; + return std::unexpected(result_code::other); } KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_history_db_, &cursor) != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - return result; + return std::unexpected(result_code::other); } auto key_hash = kth_db_make_value(key.size(), const_cast(key).data()); @@ -188,14 +187,14 @@ domain::chain::history_compact::list internal_database_basis::get_history kth_db_cursor_close(cursor); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return result; + return std::unexpected(result_code::other); } return result; } template -std::vector internal_database_basis::get_history_txns(short_hash const& key, size_t limit, size_t from_height) const { +std::expected, result_code> internal_database_basis::get_history_txns(short_hash const& key, size_t limit, size_t from_height) const { std::set temp; std::vector result; @@ -207,13 +206,13 @@ std::vector internal_database_basis::get_history_txns(short_ KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return result; + return std::unexpected(result_code::other); } KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_history_db_, &cursor) != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - return result; + return std::unexpected(result_code::other); } auto key_hash = kth_db_make_value(key.size(), const_cast(key).data());; @@ -259,7 +258,7 @@ std::vector internal_database_basis::get_history_txns(short_ kth_db_cursor_close(cursor); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return result; + return std::unexpected(result_code::other); } return result; diff --git a/src/database/include/kth/database/databases/internal_database.hpp b/src/database/include/kth/database/databases/internal_database.hpp index 502d5ba0..11a5eafd 100644 --- a/src/database/include/kth/database/databases/internal_database.hpp +++ b/src/database/include/kth/database/databases/internal_database.hpp @@ -5,7 +5,9 @@ #ifndef KTH_DATABASE_INTERNAL_DATABASE_HPP_ #define KTH_DATABASE_INTERNAL_DATABASE_HPP_ +#include #include +#include #include #include @@ -100,16 +102,33 @@ struct KD_API internal_database_basis { //TODO(fernando): optimization: consider passing a list of outputs to insert and a list of inputs to delete instead of an entire Block. // avoiding inserting and erasing internal spenders result_code push_block(domain::chain::block const& block, uint32_t height, uint32_t median_time_past); + + // Headers-first sync: store header without full block data (ABLA state = zeros) + result_code push_header(domain::chain::header const& header, uint32_t height); + + // Headers-first sync: store header with explicit ABLA state + result_code push_header(domain::chain::header const& header, uint32_t height, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size); + + // Headers-first sync: store multiple headers in a single transaction (batch) + // start_height is the height of the first header in the list + result_code push_headers_batch(domain::chain::header::list const& headers, uint32_t start_height); #endif - utxo_entry get_utxo(domain::chain::output_point const& point) const; + std::expected get_utxo(domain::chain::output_point const& point) const; - result_code get_last_height(uint32_t& out_height) const; + // Height tracking via properties table + // Returns pair of (header_height, block_height) or error + std::expected, result_code> get_last_heights() const; + +#if ! defined(KTH_DB_READONLY) + result_code set_last_header_height(uint32_t height); + result_code set_last_block_height(uint32_t height); +#endif - std::pair get_header(hash_digest const& hash) const; - domain::chain::header get_header(uint32_t height) const; - domain::chain::header::list get_headers(uint32_t from, uint32_t to) const; - std::optional get_header_and_abla_state(uint32_t height) const; + std::expected, result_code> get_header(hash_digest const& hash) const; + std::expected get_header(uint32_t height) const; + std::expected get_headers(uint32_t from, uint32_t to) const; + std::expected get_header_and_abla_state(uint32_t height) const; #if ! defined(KTH_DB_READONLY) result_code pop_block(domain::chain::block& out_block); @@ -117,23 +136,23 @@ struct KD_API internal_database_basis { result_code prune(); #endif - std::pair get_utxo_pool_from(uint32_t from, uint32_t to) const; + std::expected get_utxo_pool_from(uint32_t from, uint32_t to) const; //bool set_fast_flags_environment(bool enabled); - std::pair get_block(hash_digest const& hash) const; - domain::chain::block get_block(uint32_t height) const; + std::expected, result_code> get_block(hash_digest const& hash) const; + std::expected get_block(uint32_t height) const; - transaction_entry get_transaction(hash_digest const& hash, size_t fork_height) const; + std::expected get_transaction(hash_digest const& hash, size_t fork_height) const; - domain::chain::history_compact::list get_history(short_hash const& key, size_t limit, size_t from_height) const; - std::vector get_history_txns(short_hash const& key, size_t limit, size_t from_height) const; + std::expected get_history(short_hash const& key, size_t limit, size_t from_height) const; + std::expected, result_code> get_history_txns(short_hash const& key, size_t limit, size_t from_height) const; - domain::chain::input_point get_spend(domain::chain::output_point const& point) const; + std::expected get_spend(domain::chain::output_point const& point) const; - std::vector get_all_transaction_unconfirmed() const; + std::expected, result_code> get_all_transaction_unconfirmed() const; - transaction_unconfirmed_entry get_transaction_unconfirmed(hash_digest const& hash) const; + std::expected get_transaction_unconfirmed(hash_digest const& hash) const; #if ! defined(KTH_DB_READONLY) result_code push_transaction_unconfirmed(domain::chain::transaction const& tx, uint32_t height); @@ -143,10 +162,18 @@ struct KD_API internal_database_basis { #if ! defined(KTH_DB_READONLY) bool create_db_mode_property(); + bool create_height_properties(); #endif bool verify_db_mode_property() const; + // Property helpers (with transaction) + std::expected get_property_height(property_code prop, KTH_DB_txn* db_txn) const; +#if ! defined(KTH_DB_READONLY) + result_code set_property_height(property_code prop, uint32_t height); + result_code set_property_height(property_code prop, uint32_t height, KTH_DB_txn* db_txn); +#endif + bool open_internal(); bool is_old_block(domain::chain::block const& block) const; @@ -159,7 +186,7 @@ struct KD_API internal_database_basis { bool open_databases(); - utxo_entry get_utxo(domain::chain::output_point const& point, KTH_DB_txn* db_txn) const; + std::expected get_utxo(domain::chain::output_point const& point, KTH_DB_txn* db_txn) const; #if ! defined(KTH_DB_READONLY) result_code insert_reorg_pool(uint32_t height, KTH_DB_val& key, KTH_DB_txn* db_txn); @@ -185,6 +212,12 @@ struct KD_API internal_database_basis { result_code push_block_header(domain::chain::block const& block, uint32_t height, KTH_DB_txn* db_txn); + // Headers-first sync: store header only (without block data) + result_code push_header_only(domain::chain::header const& header, uint32_t height, KTH_DB_txn* db_txn); + + // Headers-first sync: store header with explicit ABLA state + result_code push_header_with_abla(domain::chain::header const& header, uint32_t height, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size, KTH_DB_txn* db_txn); + result_code push_block_reorg(domain::chain::block const& block, uint32_t height, KTH_DB_txn* db_txn); result_code push_block(domain::chain::block const& block, uint32_t height, uint32_t median_time_past, bool insert_reorg, KTH_DB_txn* db_txn); @@ -215,11 +248,11 @@ struct KD_API internal_database_basis { result_code remove_block(domain::chain::block const& block, uint32_t height, KTH_DB_txn* db_txn); #endif - domain::chain::header get_header(uint32_t height, KTH_DB_txn* db_txn) const; - std::optional get_header_and_abla_state(uint32_t height, KTH_DB_txn* db_txn) const; + std::expected get_header(uint32_t height, KTH_DB_txn* db_txn) const; + std::expected get_header_and_abla_state(uint32_t height, KTH_DB_txn* db_txn) const; - domain::chain::block get_block_reorg(uint32_t height, KTH_DB_txn* db_txn) const; - domain::chain::block get_block_reorg(uint32_t height) const; + std::expected get_block_reorg(uint32_t height, KTH_DB_txn* db_txn) const; + std::expected get_block_reorg(uint32_t height) const; #if ! defined(KTH_DB_READONLY) result_code remove_block(domain::chain::block const& block, uint32_t height); @@ -227,7 +260,7 @@ struct KD_API internal_database_basis { result_code prune_reorg_block(uint32_t amount_to_delete, KTH_DB_txn* db_txn); #endif - result_code get_first_reorg_block_height(uint32_t& out_height) const; + std::expected get_first_reorg_block_height() const; //TODO(fernando): is taking KTH_DB_val by value, is that Ok? result_code insert_reorg_into_pool(utxo_pool_t& pool, KTH_DB_val key_point, KTH_DB_txn* db_txn) const; @@ -236,9 +269,9 @@ struct KD_API internal_database_basis { result_code remove_blocks_db(uint32_t height, KTH_DB_txn* db_txn); #endif - domain::chain::block get_block(uint32_t height, KTH_DB_txn* db_txn) const; + std::expected get_block(uint32_t height, KTH_DB_txn* db_txn) const; - domain::chain::block get_block(hash_digest const& hash, KTH_DB_txn* db_txn) const; + std::expected get_block(hash_digest const& hash, KTH_DB_txn* db_txn) const; #if ! defined(KTH_DB_READONLY) result_code insert_block(domain::chain::block const& block, uint32_t height, uint64_t tx_count, KTH_DB_txn* db_txn); diff --git a/src/database/include/kth/database/databases/internal_database.ipp b/src/database/include/kth/database/databases/internal_database.ipp index 1e927ac7..f9168491 100644 --- a/src/database/include/kth/database/databases/internal_database.ipp +++ b/src/database/include/kth/database/databases/internal_database.ipp @@ -7,9 +7,11 @@ // #include #include +#include namespace kth::database { +//TODO: unordered_flat_map o concurrent_flat_map (necesitamos thread safety?) using utxo_pool_t = std::unordered_map; template @@ -53,12 +55,16 @@ bool internal_database_basis::create() { return false; } + ret = create_height_properties(); + if ( ! ret ) { + return false; + } + return true; } template bool internal_database_basis::create_db_mode_property() { - KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, 0, &db_txn); if (res != KTH_DB_SUCCESS) { @@ -84,8 +90,144 @@ bool internal_database_basis::create_db_mode_property() { return true; } +template +bool internal_database_basis::create_height_properties() { + KTH_DB_txn* db_txn; + auto res = kth_db_txn_begin(env_, NULL, 0, &db_txn); + if (res != KTH_DB_SUCCESS) { + return false; + } + + // Initialize last_header_height to 0 + uint32_t initial_height = 0; + property_code header_prop = property_code::last_header_height; + auto header_key = kth_db_make_value(sizeof(header_prop), &header_prop); + auto header_value = kth_db_make_value(sizeof(initial_height), &initial_height); + + res = kth_db_put(db_txn, dbi_properties_, &header_key, &header_value, KTH_DB_NOOVERWRITE); + if (res != KTH_DB_SUCCESS) { + spdlog::error("[database] Failed saving last_header_height in DB Properties [create_height_properties] {}", static_cast(res)); + kth_db_txn_abort(db_txn); + return false; + } + + // Initialize last_block_height to 0 + property_code block_prop = property_code::last_block_height; + auto block_key = kth_db_make_value(sizeof(block_prop), &block_prop); + auto block_value = kth_db_make_value(sizeof(initial_height), &initial_height); + + res = kth_db_put(db_txn, dbi_properties_, &block_key, &block_value, KTH_DB_NOOVERWRITE); + if (res != KTH_DB_SUCCESS) { + spdlog::error("[database] Failed saving last_block_height in DB Properties [create_height_properties] {}", static_cast(res)); + kth_db_txn_abort(db_txn); + return false; + } + + res = kth_db_txn_commit(db_txn); + if (res != KTH_DB_SUCCESS) { + return false; + } + + return true; +} + #endif // ! defined(KTH_DB_READONLY) +// ============================================================================= +// Height Properties - Get/Set +// ============================================================================= + +template +std::expected internal_database_basis::get_property_height(property_code prop, KTH_DB_txn* db_txn) const { + auto key = kth_db_make_value(sizeof(prop), &prop); + + KTH_DB_val value; + auto res = kth_db_get(db_txn, dbi_properties_, &key, &value); + if (res == KTH_DB_NOTFOUND) { + return std::unexpected(result_code::key_not_found); + } + if (res != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); + } + + return *static_cast(kth_db_get_data(value)); +} + +template +std::expected, result_code> internal_database_basis::get_last_heights() const { + KTH_DB_txn* db_txn; + auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); + if (res != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); + } + + auto header_result = get_property_height(property_code::last_header_height, db_txn); + if ( ! header_result) { + kth_db_txn_commit(db_txn); + return std::unexpected(header_result.error()); + } + + auto block_result = get_property_height(property_code::last_block_height, db_txn); + if ( ! block_result) { + kth_db_txn_commit(db_txn); + return std::unexpected(block_result.error()); + } + + if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); + } + + return std::pair{*header_result, *block_result}; +} + +#if ! defined(KTH_DB_READONLY) + +template +result_code internal_database_basis::set_property_height(property_code prop, uint32_t height) { + KTH_DB_txn* db_txn; + auto res = kth_db_txn_begin(env_, NULL, 0, &db_txn); + if (res != KTH_DB_SUCCESS) { + return result_code::other; + } + + auto result = set_property_height(prop, height, db_txn); + if (result != result_code::success) { + kth_db_txn_abort(db_txn); + return result; + } + + if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { + return result_code::other; + } + + return result_code::success; +} + +template +result_code internal_database_basis::set_property_height(property_code prop, uint32_t height, KTH_DB_txn* db_txn) { + auto key = kth_db_make_value(sizeof(prop), &prop); + auto value = kth_db_make_value(sizeof(height), &height); + + auto res = kth_db_put(db_txn, dbi_properties_, &key, &value, 0); // 0 = overwrite if exists + if (res != KTH_DB_SUCCESS) { + spdlog::error("[database] Failed updating height property in DB Properties [set_property_height] {}", static_cast(res)); + return result_code::other; + } + + return result_code::success; +} + +template +result_code internal_database_basis::set_last_header_height(uint32_t height) { + return set_property_height(property_code::last_header_height, height); +} + +template +result_code internal_database_basis::set_last_block_height(uint32_t height) { + return set_property_height(property_code::last_block_height, height); +} + +#endif // ! defined(KTH_DB_READONLY) template bool internal_database_basis::open() { @@ -154,10 +296,10 @@ bool internal_database_basis::verify_db_mode_property() const { template bool internal_database_basis::close() { if (db_opened_) { - - //TODO(fernando): check sync - //Force synchronous flush (use with KTH_DB_NOSYNC or MDB_NOMETASYNC, with other flags do nothing) + // Force synchronous flush (use with KTH_DB_NOSYNC or MDB_NOMETASYNC) kth_db_env_sync(env_, true); + + // Close all DBIs before closing the environment kth_db_dbi_close(env_, dbi_block_header_); kth_db_dbi_close(env_, dbi_block_header_by_hash_); kth_db_dbi_close(env_, dbi_utxo_); @@ -177,6 +319,7 @@ bool internal_database_basis::close() { kth_db_dbi_close(env_, dbi_spend_db_); kth_db_dbi_close(env_, dbi_transaction_unconfirmed_db_); } + db_opened_ = false; } @@ -245,168 +388,182 @@ result_code internal_database_basis::push_block(domain::chain::block cons template -utxo_entry internal_database_basis::get_utxo(domain::chain::output_point const& point, KTH_DB_txn* db_txn) const { - +std::expected internal_database_basis::get_utxo(domain::chain::output_point const& point, KTH_DB_txn* db_txn) const { auto keyarr = point.to_data(KTH_INTERNAL_DB_WIRE); auto key = kth_db_make_value(keyarr.size(), keyarr.data()); KTH_DB_val value; auto res0 = kth_db_get(db_txn, dbi_utxo_, &key, &value); + if (res0 == KTH_DB_NOTFOUND) { + return std::unexpected(result_code::key_not_found); + } if (res0 != KTH_DB_SUCCESS) { - return utxo_entry{}; + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); byte_reader reader(data); auto res = utxo_entry::from_data(reader); if ( ! res) { - return utxo_entry{}; + return std::unexpected(result_code::other); } return *res; } template -utxo_entry internal_database_basis::get_utxo(domain::chain::output_point const& point) const { - +std::expected internal_database_basis::get_utxo(domain::chain::output_point const& point) const { KTH_DB_txn* db_txn; auto res0 = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res0 != KTH_DB_SUCCESS) { spdlog::error("[database] Error begining LMDB Transaction [get_utxo] {}", res0); - return {}; + return std::unexpected(result_code::other); } auto ret = get_utxo(point, db_txn); - res0 = kth_db_txn_commit(db_txn); - if (res0 != KTH_DB_SUCCESS) { + if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { spdlog::error("[database] Error commiting LMDB Transaction [get_utxo] {}", res0); - return {}; + return std::unexpected(result_code::other); } return ret; } -template -result_code internal_database_basis::get_last_height(uint32_t& out_height) const { - KTH_DB_txn* db_txn; - auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); - if (res != KTH_DB_SUCCESS) { - return result_code::other; - } - - KTH_DB_cursor* cursor; - if (kth_db_cursor_open(db_txn, dbi_block_header_, &cursor) != KTH_DB_SUCCESS) { - kth_db_txn_commit(db_txn); - return result_code::other; - } - - KTH_DB_val key; - int rc; - if ((rc = kth_db_cursor_get(cursor, &key, nullptr, KTH_DB_LAST)) != KTH_DB_SUCCESS) { - return result_code::db_empty; - } - - // assert kth_db_get_size(key) == 4; - out_height = *static_cast(kth_db_get_data(key)); - - kth_db_cursor_close(cursor); - - // kth_db_txn_abort(db_txn); - if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return result_code::other; - } - - return result_code::success; -} +// Deprecated: use get_last_heights() instead +// template +// result_code internal_database_basis::get_last_height(uint32_t& out_height) const { +// KTH_DB_txn* db_txn; +// auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); +// if (res != KTH_DB_SUCCESS) { +// return result_code::other; +// } +// +// KTH_DB_cursor* cursor; +// if (kth_db_cursor_open(db_txn, dbi_block_header_, &cursor) != KTH_DB_SUCCESS) { +// kth_db_txn_commit(db_txn); +// return result_code::other; +// } +// +// KTH_DB_val key; +// int rc; +// if ((rc = kth_db_cursor_get(cursor, &key, nullptr, KTH_DB_LAST)) != KTH_DB_SUCCESS) { +// return result_code::db_empty; +// } +// +// // assert kth_db_get_size(key) == 4; +// out_height = *static_cast(kth_db_get_data(key)); +// +// kth_db_cursor_close(cursor); +// +// // kth_db_txn_abort(db_txn); +// if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { +// return result_code::other; +// } +// +// return result_code::success; +// } template -std::pair internal_database_basis::get_header(hash_digest const& hash) const { +std::expected, result_code> internal_database_basis::get_header(hash_digest const& hash) const { auto key = kth_db_make_value(hash.size(), const_cast(hash).data()); KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } KTH_DB_val value; - if (kth_db_get(db_txn, dbi_block_header_by_hash_, &key, &value) != KTH_DB_SUCCESS) { + auto res0 = kth_db_get(db_txn, dbi_block_header_by_hash_, &key, &value); + if (res0 == KTH_DB_NOTFOUND) { + kth_db_txn_commit(db_txn); + return std::unexpected(result_code::key_not_found); + } + if (res0 != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - // kth_db_txn_abort(db_txn); - return {}; + return std::unexpected(result_code::other); } // assert kth_db_get_size(value) == 4; auto height = *static_cast(kth_db_get_data(value)); - auto header = get_header(height, db_txn); + auto header_result = get_header(height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - return {header, height}; + if ( ! header_result) { + return std::unexpected(header_result.error()); + } + + return std::make_pair(*header_result, height); } template -domain::chain::header internal_database_basis::get_header(uint32_t height) const { +std::expected internal_database_basis::get_header(uint32_t height) const { KTH_DB_txn* db_txn; auto ret1 = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (ret1 != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - auto ret2 = get_header(height, db_txn); + auto result = get_header(height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - return ret2; + return result; } template -std::optional internal_database_basis::get_header_and_abla_state(uint32_t height) const { +std::expected internal_database_basis::get_header_and_abla_state(uint32_t height) const { KTH_DB_txn* db_txn; auto zzz = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (zzz != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - auto res = get_header_and_abla_state(height, db_txn); + auto result = get_header_and_abla_state(height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - return res; + return result; } template -domain::chain::header::list internal_database_basis::get_headers(uint32_t from, uint32_t to) const { +std::expected internal_database_basis::get_headers(uint32_t from, uint32_t to) const { // precondition: from <= to domain::chain::header::list list; KTH_DB_txn* db_txn; auto zzz = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (zzz != KTH_DB_SUCCESS) { - return list; + return std::unexpected(result_code::other); } KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_block_header_, &cursor) != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - return list; + return std::unexpected(result_code::other); } auto key = kth_db_make_value(sizeof(from), &from); KTH_DB_val value; int rc = kth_db_cursor_get(cursor, &key, &value, KTH_DB_SET); + if (rc == KTH_DB_NOTFOUND) { + kth_db_cursor_close(cursor); + kth_db_txn_commit(db_txn); + return std::unexpected(result_code::key_not_found); + } if (rc != KTH_DB_SUCCESS) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return list; + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); @@ -436,25 +593,25 @@ domain::chain::header::list internal_database_basis::get_headers(uint32_t template result_code internal_database_basis::pop_block(domain::chain::block& out_block) { - uint32_t height; - //TODO: (Mario) use only one transaction ? //TODO: (Mario) add overload with tx // The blockchain is empty (nothing to pop, not even genesis). - auto res = get_last_height(height); - if (res != result_code::success ) { - return res; + auto heights_result = get_last_heights(); + if ( ! heights_result) { + return heights_result.error(); } + auto const height = heights_result->first; // header_height //TODO: (Mario) add overload with tx // This should never become invalid if this call is protected. - out_block = get_block_reorg(height); - if ( ! out_block.is_valid()) { - return result_code::key_not_found; + auto block_result = get_block_reorg(height); + if ( ! block_result) { + return block_result.error(); } + out_block = std::move(*block_result); - res = remove_block(out_block, height); + auto res = remove_block(out_block, height); if (res != result_code::success) { return res; } @@ -465,17 +622,21 @@ result_code internal_database_basis::pop_block(domain::chain::block& out_ template result_code internal_database_basis::prune() { //TODO: (Mario) add overload with tx - uint32_t last_height; - auto res = get_last_height(last_height); - - if (res == result_code::db_empty) return result_code::no_data_to_prune; - if (res != result_code::success) return res; + auto heights_result = get_last_heights(); + if ( ! heights_result) { + auto const err = heights_result.error(); + if (err == result_code::db_empty) return result_code::no_data_to_prune; + return err; + } + auto const last_height = heights_result->first; // header_height if (last_height < reorg_pool_limit_) return result_code::no_data_to_prune; - uint32_t first_height; - res = get_first_reorg_block_height(first_height); - if (res == result_code::db_empty) return result_code::no_data_to_prune; - if (res != result_code::success) return res; + auto first_height_result = get_first_reorg_block_height(); + if ( ! first_height_result) { + if (first_height_result.error() == result_code::db_empty) return result_code::no_data_to_prune; + return first_height_result.error(); + } + auto const first_height = *first_height_result; if (first_height > last_height) return result_code::db_corrupt; auto reorg_count = last_height - first_height + 1; @@ -490,7 +651,7 @@ result_code internal_database_basis::prune() { return result_code::other; } - res = prune_reorg_block(amount_to_delete, db_txn); + auto res = prune_reorg_block(amount_to_delete, db_txn); if (res != result_code::success) { kth_db_txn_abort(db_txn); return res; @@ -550,20 +711,20 @@ result_code internal_database_basis::insert_reorg_into_pool(utxo_pool_t& } template -std::pair internal_database_basis::get_utxo_pool_from(uint32_t from, uint32_t to) const { +std::expected internal_database_basis::get_utxo_pool_from(uint32_t from, uint32_t to) const { // precondition: from <= to utxo_pool_t pool; KTH_DB_txn* db_txn; auto zzz = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (zzz != KTH_DB_SUCCESS) { - return {result_code::other, pool}; + return std::unexpected(result_code::other); } KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_reorg_index_, &cursor) != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - return {result_code::other, pool}; + return std::unexpected(result_code::other); } auto key = kth_db_make_value(sizeof(from), &from); @@ -574,31 +735,31 @@ std::pair internal_database_basis::get_utxo_poo if (rc != KTH_DB_SUCCESS) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return {result_code::key_not_found, pool}; + return std::unexpected(result_code::key_not_found); } auto current_height = *static_cast(kth_db_get_data(key)); if (current_height < from) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return {result_code::other, pool}; + return std::unexpected(result_code::other); } // if (current_height > from) { // kth_db_cursor_close(cursor); // kth_db_txn_commit(db_txn); - // return {result_code::other, pool}; + // return std::unexpected(result_code::other); // } if (current_height > to) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return {result_code::other, pool}; + return std::unexpected(result_code::other); } auto res = insert_reorg_into_pool(pool, value, db_txn); if (res != result_code::success) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return {res, pool}; + return std::unexpected(res); } while ((rc = kth_db_cursor_get(cursor, &key, &value, KTH_DB_NEXT)) == KTH_DB_SUCCESS) { @@ -606,24 +767,24 @@ std::pair internal_database_basis::get_utxo_poo if (current_height > to) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return {result_code::other, pool}; + return std::unexpected(result_code::other); } res = insert_reorg_into_pool(pool, value, db_txn); if (res != result_code::success) { kth_db_cursor_close(cursor); kth_db_txn_commit(db_txn); - return {res, pool}; + return std::unexpected(res); } } kth_db_cursor_close(cursor); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {result_code::other, pool}; + return std::unexpected(result_code::other); } - return {result_code::success, pool}; + return pool; } #if ! defined(KTH_DB_READONLY) @@ -678,11 +839,15 @@ size_t internal_database_basis::adjust_db_size(size_t size) const { template bool internal_database_basis::create_and_open_environment() { + spdlog::debug("[internal_database] create_and_open_environment() - starting"); + spdlog::default_logger()->flush(); if (kth_db_env_create(&env_) != KTH_DB_SUCCESS) { return false; } env_created_ = true; + spdlog::debug("[internal_database] create_and_open_environment() - env created, env_={}", (void*)env_); + spdlog::default_logger()->flush(); // TODO(fernando): see what to do with mdb_env_set_maxreaders ---------------------------------------------- // int threads = tools::get_max_concurrency(); @@ -773,13 +938,19 @@ template bool internal_database_basis::open_databases() { KTH_DB_txn* db_txn; + spdlog::debug("[internal_database] open_databases() - starting, thread_id={}", std::hash{}(std::this_thread::get_id())); + spdlog::default_logger()->flush(); + auto res = kth_db_txn_begin(env_, NULL, KTH_DB_CONDITIONAL_READONLY, &db_txn); if (res != KTH_DB_SUCCESS) { + spdlog::error("[internal_database] open_databases() - failed to begin transaction: {}", res); return false; } auto open_db = [&](auto const& db_name, uint32_t flags, KTH_DB_dbi* dbi){ auto result = kth_db_dbi_open(db_txn, db_name, flags, dbi); + spdlog::debug("[internal_database] open_databases() - opened {}: result={}, dbi={}", db_name, result, *dbi); + spdlog::default_logger()->flush(); if (result != KTH_DB_SUCCESS) { kth_db_txn_abort(db_txn); } @@ -809,7 +980,10 @@ bool internal_database_basis::open_databases() { mdb_set_dupsort(db_txn, dbi_history_db_, compare_uint64); } - db_opened_ = kth_db_txn_commit(db_txn) == KTH_DB_SUCCESS; + auto commit_res = kth_db_txn_commit(db_txn); + db_opened_ = commit_res == KTH_DB_SUCCESS; + spdlog::debug("[internal_database] open_databases() - commit result={}, db_opened_={}", commit_res, db_opened_); + spdlog::default_logger()->flush(); return db_opened_; } @@ -978,6 +1152,12 @@ result_code internal_database_basis::push_block(domain::chain::block cons return res; } + // Update last_block_height property + auto height_res = set_property_height(property_code::last_block_height, height, db_txn); + if (height_res != result_code::success) { + return height_res; + } + if (res == result_code::success_duplicate_coinbase) return res; @@ -1017,7 +1197,12 @@ result_code internal_database_basis::push_genesis(domain::chain::block co res = insert_block(block, 0, 0, db_txn); } - return res; + if (res != result_code::success) { + return res; + } + + // Update last_block_height property for genesis block + return set_property_height(property_code::last_block_height, 0, db_txn); } template @@ -1145,6 +1330,18 @@ result_code internal_database_basis::remove_block(domain::chain::block co } } + // Update last_block_height and last_header_height to height - 1 (new chain tip) + auto const new_height = height > 0 ? height - 1 : 0; + res = set_property_height(property_code::last_block_height, new_height, db_txn); + if (res != result_code::success) { + return res; + } + + res = set_property_height(property_code::last_header_height, new_height, db_txn); + if (res != result_code::success) { + return res; + } + return result_code::success; } @@ -1175,3 +1372,4 @@ result_code internal_database_basis::remove_block(domain::chain::block co } // namespace kth::database #endif // KTH_DATABASE_INTERNAL_DATABASE_IPP_ + diff --git a/src/database/include/kth/database/databases/property_code.hpp b/src/database/include/kth/database/databases/property_code.hpp index 9c720c77..ce6d0108 100644 --- a/src/database/include/kth/database/databases/property_code.hpp +++ b/src/database/include/kth/database/databases/property_code.hpp @@ -17,6 +17,8 @@ namespace kth::database { enum class property_code { db_mode = 0, + last_header_height = 1, + last_block_height = 2, }; enum class db_mode_type { diff --git a/src/database/include/kth/database/databases/reorg_database.ipp b/src/database/include/kth/database/databases/reorg_database.ipp index d35944bf..241ed406 100644 --- a/src/database/include/kth/database/databases/reorg_database.ipp +++ b/src/database/include/kth/database/databases/reorg_database.ipp @@ -145,38 +145,42 @@ result_code internal_database_basis::remove_reorg_index(uint32_t height, #endif // ! defined(KTH_DB_READONLY) template -domain::chain::block internal_database_basis::get_block_reorg(uint32_t height, KTH_DB_txn* db_txn) const { +std::expected internal_database_basis::get_block_reorg(uint32_t height, KTH_DB_txn* db_txn) const { auto key = kth_db_make_value(sizeof(height), &height); KTH_DB_val value; - if (kth_db_get(db_txn, dbi_reorg_block_, &key, &value) != KTH_DB_SUCCESS) { - return {}; + auto res0 = kth_db_get(db_txn, dbi_reorg_block_, &key, &value); + if (res0 == KTH_DB_NOTFOUND) { + return std::unexpected(result_code::key_not_found); + } + if (res0 != KTH_DB_SUCCESS) { + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); byte_reader reader(data); //TODO(fernando): mover fuera de la DbTx auto res = domain::chain::block::from_data(reader); if ( ! res) { - return domain::chain::block{}; + return std::unexpected(result_code::other); } return *res; } template -domain::chain::block internal_database_basis::get_block_reorg(uint32_t height) const { +std::expected internal_database_basis::get_block_reorg(uint32_t height) const { KTH_DB_txn* db_txn; auto zzz = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (zzz != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - auto res = get_block_reorg(height, db_txn); + auto result = get_block_reorg(height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } - return res; + return result; } #if ! defined(KTH_DB_READONLY) @@ -243,36 +247,38 @@ result_code internal_database_basis::prune_reorg_block(uint32_t amount_to #endif // ! defined(KTH_DB_READONLY) template -result_code internal_database_basis::get_first_reorg_block_height(uint32_t& out_height) const { +std::expected internal_database_basis::get_first_reorg_block_height() const { KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return result_code::other; + return std::unexpected(result_code::other); } KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_reorg_block_, &cursor) != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - return result_code::other; + return std::unexpected(result_code::other); } KTH_DB_val key; int rc; if ((rc = kth_db_cursor_get(cursor, &key, nullptr, KTH_DB_FIRST)) != KTH_DB_SUCCESS) { - return result_code::db_empty; + kth_db_cursor_close(cursor); + kth_db_txn_commit(db_txn); + return std::unexpected(result_code::db_empty); } // assert kth_db_get_size(key) == 4; - out_height = *static_cast(kth_db_get_data(key)); + auto height = *static_cast(kth_db_get_data(key)); kth_db_cursor_close(cursor); // kth_db_txn_abort(db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return result_code::other; + return std::unexpected(result_code::other); } - return result_code::success; + return height; } diff --git a/src/database/include/kth/database/databases/spend_database.ipp b/src/database/include/kth/database/databases/spend_database.ipp index 17857f18..96a8a6b7 100644 --- a/src/database/include/kth/database/databases/spend_database.ipp +++ b/src/database/include/kth/database/databases/spend_database.ipp @@ -11,7 +11,7 @@ namespace kth::database { //public template -domain::chain::input_point internal_database_basis::get_spend(domain::chain::output_point const& point) const { +std::expected internal_database_basis::get_spend(domain::chain::output_point const& point) const { auto keyarr = point.to_data(KTH_INTERNAL_DB_WIRE); auto key = kth_db_make_value(keyarr.size(), keyarr.data()); @@ -21,14 +21,17 @@ domain::chain::input_point internal_database_basis::get_spend(domain::cha auto res0 = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res0 != KTH_DB_SUCCESS) { spdlog::info("[database] Error begining LMDB Transaction [get_spend] {}", res0); - return domain::chain::input_point{}; + return std::unexpected(result_code::other); } res0 = kth_db_get(db_txn, dbi_spend_db_, &key, &value); + if (res0 == KTH_DB_NOTFOUND) { + kth_db_txn_commit(db_txn); + return std::unexpected(result_code::key_not_found); + } if (res0 != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - // kth_db_txn_abort(db_txn); - return domain::chain::input_point{}; + return std::unexpected(result_code::other); } auto data = db_value_to_data_chunk(value); @@ -36,13 +39,13 @@ domain::chain::input_point internal_database_basis::get_spend(domain::cha res0 = kth_db_txn_commit(db_txn); if (res0 != KTH_DB_SUCCESS) { spdlog::debug("[database] Error commiting LMDB Transaction [get_spend] {}", res0); - return domain::chain::input_point{}; + return std::unexpected(result_code::other); } byte_reader reader(data); auto res_input = domain::chain::input_point::from_data(reader); if ( ! res_input) { - return domain::chain::input_point{}; + return std::unexpected(result_code::other); } return *res_input; } diff --git a/src/database/include/kth/database/databases/transaction_database.ipp b/src/database/include/kth/database/databases/transaction_database.ipp index e3410b1d..c8e56634 100644 --- a/src/database/include/kth/database/databases/transaction_database.ipp +++ b/src/database/include/kth/database/databases/transaction_database.ipp @@ -11,18 +11,22 @@ namespace kth::database { //public template -transaction_entry internal_database_basis::get_transaction(hash_digest const& hash, size_t fork_height) const { +std::expected internal_database_basis::get_transaction(hash_digest const& hash, size_t fork_height) const { KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return transaction_entry{}; + return std::unexpected(result_code::other); } auto entry = get_transaction(hash, fork_height, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return transaction_entry{}; + return std::unexpected(result_code::other); + } + + if ( ! entry.is_valid()) { + return std::unexpected(result_code::key_not_found); } return entry; diff --git a/src/database/include/kth/database/databases/transaction_unconfirmed_database.ipp b/src/database/include/kth/database/databases/transaction_unconfirmed_database.ipp index dc139564..45c66f25 100644 --- a/src/database/include/kth/database/databases/transaction_unconfirmed_database.ipp +++ b/src/database/include/kth/database/databases/transaction_unconfirmed_database.ipp @@ -10,18 +10,22 @@ namespace kth::database { template -transaction_unconfirmed_entry internal_database_basis::get_transaction_unconfirmed(hash_digest const& hash) const { +std::expected internal_database_basis::get_transaction_unconfirmed(hash_digest const& hash) const { KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); } auto const& ret = get_transaction_unconfirmed(hash, db_txn); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return {}; + return std::unexpected(result_code::other); + } + + if ( ! ret.is_valid()) { + return std::unexpected(result_code::key_not_found); } return ret; @@ -46,21 +50,21 @@ transaction_unconfirmed_entry internal_database_basis::get_transaction_un } template -std::vector internal_database_basis::get_all_transaction_unconfirmed() const { +std::expected, result_code> internal_database_basis::get_all_transaction_unconfirmed() const { std::vector result; KTH_DB_txn* db_txn; auto res = kth_db_txn_begin(env_, NULL, KTH_DB_RDONLY, &db_txn); if (res != KTH_DB_SUCCESS) { - return result; + return std::unexpected(result_code::other); } KTH_DB_cursor* cursor; if (kth_db_cursor_open(db_txn, dbi_transaction_unconfirmed_db_, &cursor) != KTH_DB_SUCCESS) { kth_db_txn_commit(db_txn); - return result; + return std::unexpected(result_code::other); } KTH_DB_val key; @@ -90,7 +94,7 @@ std::vector internal_database_basis::get_a kth_db_cursor_close(cursor); if (kth_db_txn_commit(db_txn) != KTH_DB_SUCCESS) { - return result; + return std::unexpected(result_code::other); } return result; diff --git a/src/database/include/kth/database/settings.hpp b/src/database/include/kth/database/settings.hpp index 85a14fc5..018fb16a 100644 --- a/src/database/include/kth/database/settings.hpp +++ b/src/database/include/kth/database/settings.hpp @@ -25,6 +25,10 @@ struct KD_API settings { uint64_t db_max_size; bool safe_mode; uint32_t cache_capacity; + + /// Use parallel block push (true) or sequential (false). + /// Parallel may not provide benefits due to LMDB serialization. + bool parallel_block_push; }; } // namespace kth::database diff --git a/src/database/src/data_base.cpp b/src/database/src/data_base.cpp index 18d0021e..7bd5a29f 100644 --- a/src/database/src/data_base.cpp +++ b/src/database/src/data_base.cpp @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -20,6 +20,11 @@ #include #include +#include +#include +#include +#include + namespace kth::database { using namespace kth::domain::chain; @@ -27,7 +32,6 @@ using namespace kth::config; using namespace kth::domain::wallet; using namespace boost::adaptors; using namespace std::filesystem; -using namespace std::placeholders; #define NAME "data_base" @@ -70,8 +74,10 @@ bool data_base::create(block const& genesis) { } // Store the first block. - // push(genesis, 0); - push_genesis(genesis); + auto res = push_genesis(genesis); + if (res != error::success) { + return false; + } closed_ = false; return true; @@ -95,8 +101,7 @@ bool data_base::close() { } closed_ = true; - auto const closed = internal_db_->close(); - return closed; + return internal_db_->close(); } // protected @@ -119,20 +124,24 @@ internal_database const& data_base::internal_db() const { // ---------------------------------------------------------------------------- static inline -uint32_t get_next_height(internal_database const& db) { - uint32_t current_height; - auto res = db.get_last_height(current_height); - - if (res != result_code::success) { +uint32_t get_next_header_height(internal_database const& db) { + auto result = db.get_last_heights(); + if ( ! result) { return 0; } - - return current_height + 1; + return result->first + 1; // header_height + 1 } static inline -hash_digest get_previous_hash(internal_database const& db, size_t height) { - return height == 0 ? null_hash : db.get_header(height - 1).hash(); +std::optional get_previous_hash(internal_database const& db, size_t height) { + if (height == 0) { + return std::nullopt; // Genesis block has no previous block + } + auto result = db.get_header(height - 1); + if ( ! result) { + return std::nullopt; + } + return result->hash(); } //TODO(fernando): const? @@ -143,7 +152,8 @@ code data_base::verify_insert(block const& block, size_t height) { auto res = internal_db_->get_header(height); - if (res.is_valid()) { + if (res) { + // Header already exists at this height return error::store_block_duplicate; } @@ -159,11 +169,12 @@ code data_base::verify_push(block const& block, size_t height) const { return error::success; } - if (get_next_height(internal_db()) != height) { + if (get_next_header_height(internal_db()) != height) { return error::store_block_invalid_height; } - if (block.header().previous_block_hash() != get_previous_hash(internal_db(), height)) { + auto const prev_hash = get_previous_hash(internal_db(), height); + if ( ! prev_hash || block.header().previous_block_hash() != *prev_hash) { return error::store_block_missing_parent; } @@ -219,6 +230,61 @@ code data_base::push(block const& block, size_t height) { return error::success; } +// Add a header for headers-first sync (without full block data). +// This is designed for write exclusivity and read concurrency. +code data_base::push_header(header const& header, size_t height) { + if (get_next_header_height(internal_db()) != height) { + return error::store_block_invalid_height; + } + + if (height > 0) { + auto const prev_hash = get_previous_hash(internal_db(), height); + if ( ! prev_hash || header.previous_block_hash() != *prev_hash) { + return error::store_block_missing_parent; + } + } + + auto res = internal_db_->push_header(header, height); + if ( ! succeed(res)) { + return error::database_push_failed; + } + return error::success; +} + +// Add a header with explicit ABLA state for headers-first sync. +// This is designed for write exclusivity and read concurrency. +code data_base::push_header(header const& header, size_t height, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size) { + if (get_next_header_height(internal_db()) != height) { + return error::store_block_invalid_height; + } + + if (height > 0) { + auto const prev_hash = get_previous_hash(internal_db(), height); + if ( ! prev_hash || header.previous_block_hash() != *prev_hash) { + return error::store_block_missing_parent; + } + } + + auto res = internal_db_->push_header(header, height, block_size, control_block_size, elastic_buffer_size); + if ( ! succeed(res)) { + return error::database_push_failed; + } + return error::success; +} + +// Push multiple headers in a single transaction (batch) +code data_base::push_headers_batch(header::list const& headers, size_t start_height) { + if (headers.empty()) { + return error::success; + } + + auto res = internal_db_->push_headers_batch(headers, static_cast(start_height)); + if ( ! succeed(res)) { + return error::database_push_failed; + } + return error::success; +} + // private // Add the Genesis block code data_base::push_genesis(block const& block) { @@ -284,75 +350,120 @@ bool data_base::pop_outputs(const output::list& outputs, size_t height) { } #endif //! defined(KTH_DB_READONLY) -// Asynchronous writers. +// Coroutine writers. // ---------------------------------------------------------------------------- #if ! defined(KTH_DB_READONLY) -// Add a list of blocks in order. -// If the dispatch threadpool is shut down when this is running the handler -// will never be invoked, resulting in a threadpool.join indefinite hang. -void data_base::push_all(block_const_ptr_list_const_ptr in_blocks, size_t first_height, dispatcher& dispatch, result_handler handler) { + +// Push a single block to the database (synchronous helper). +code data_base::do_push(block_const_ptr block, size_t height, uint32_t median_time_past) { + auto res = internal_db_->push_block(*block, height, median_time_past); + if ( ! succeed(res)) { + return error::database_concurrent_push_failed; + } + block->validation.end_push = asio::steady_clock::now(); + return error::success; +} + +// Push all blocks sequentially (one after another). +::asio::awaitable data_base::push_all_sequential(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height) { DEBUG_ONLY(*safe_add(in_blocks->size(), first_height)); - // This is the beginning of the push_all sequence. - push_next(error::success, in_blocks, 0, first_height, dispatch, handler); + size_t height = first_height; + for (auto const& block : *in_blocks) { + auto const median_time_past = block->header().validation.median_time_past; + + // Set push start time for the block. + block->validation.start_push = asio::steady_clock::now(); + + // Push block synchronously. + auto const ec = do_push(block, height, median_time_past); + if (ec) { + co_return ec; + } + ++height; + } + co_return error::success; } -// TODO(legacy): resolve inconsistency with height and median_time_past passing. -void data_base::push_next(code const& ec, block_const_ptr_list_const_ptr blocks, size_t index, size_t height, dispatcher& dispatch, result_handler handler) { - if (ec || index >= blocks->size()) { - // This ends the loop. - handler(ec); - return; +// Push all blocks in parallel (dispatch all, collect results). +::asio::awaitable data_base::push_all_parallel(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height) { + DEBUG_ONLY(*safe_add(in_blocks->size(), first_height)); + + auto const count = in_blocks->size(); + if (count == 0) { + co_return error::success; } - auto const block = (*blocks)[index]; - auto const median_time_past = block->header().validation.median_time_past; + using result_channel = ::asio::experimental::concurrent_channel; + auto channel = std::make_shared(executor, count); + + // Dispatch all push operations in parallel. + size_t height = first_height; + for (auto const& block : *in_blocks) { + auto const median_time_past = block->header().validation.median_time_past; + auto const block_height = height; - // Set push start time for the block. - block->validation.start_push = asio::steady_clock::now(); + // Set push start time for the block. + block->validation.start_push = asio::steady_clock::now(); - result_handler const next = std::bind(&data_base::push_next, this, _1, blocks, index + 1, height + 1, std::ref(dispatch), handler); + ::asio::post(executor, [this, block, block_height, median_time_past, channel]() { + auto const ec = do_push(block, block_height, median_time_past); + channel->try_send(std::error_code{}, ec); + }); + + ++height; + } - // This is the beginning of the block sub-sequence. - dispatch.concurrent(&data_base::do_push, this, block, height, median_time_past, std::ref(dispatch), next); + // Collect results from all parallel operations. + code final_result = error::success; + for (size_t i = 0; i < count; ++i) { + auto [ec, result] = co_await channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + // Channel error (shouldn't happen). + final_result = error::database_concurrent_push_failed; + } else if (result && !final_result) { + // Store first error encountered. + final_result = result; + } + } + + co_return final_result; } -void data_base::do_push(block_const_ptr block, size_t height, uint32_t median_time_past, dispatcher& dispatch, result_handler handler) { - // spdlog::debug("[database] Write flushed to disk: {}", ec.message()); - auto res = internal_db_->push_block(*block, height, median_time_past); - if ( ! succeed(res)) { - handler(error::database_concurrent_push_failed); //TODO(fernando): create a new operation_failed - return; +// Push all blocks starting at first_height. +// Selects parallel or sequential based on settings_.parallel_block_push. +::asio::awaitable data_base::push_all(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height) { + if (settings_.parallel_block_push) { + co_return co_await push_all_parallel(executor, in_blocks, first_height); + } else { + co_return co_await push_all_sequential(executor, in_blocks, first_height); } - block->validation.end_push = asio::steady_clock::now(); - // This is the end of the block sub-sequence. - handler(error::success); } -// TODO(legacy): make async and concurrency as appropriate. -// This precludes popping the genesis block. -void data_base::pop_above(block_const_ptr_list_ptr out_blocks, hash_digest const& fork_hash, dispatcher&, result_handler handler) { - out_blocks->clear(); +// Pop the set of blocks above the given hash. +// Returns the popped blocks or an error if the database is corrupt or the hash doesn't exist. +awaitable_expected data_base::pop_above(executor_type executor, hash_digest const& fork_hash) { + auto out_blocks = std::make_shared(); auto const header_result = internal_db_->get_header(fork_hash); + if ( ! header_result) { + co_return std::unexpected(error::chain_reorganization_failed); + } - uint32_t top; // The fork point does not exist or failed to get it or the top, fail. - if ( ! header_result.first.is_valid() || internal_db_->get_last_height(top) != result_code::success) { - //**--** - handler(error::chain_reorganization_failed); - return; + auto const heights = internal_db_->get_last_heights(); + if ( ! heights) { + co_return std::unexpected(error::chain_reorganization_failed); } + auto const top = heights->second; // block_height - auto const fork = header_result.second; - + auto const fork = header_result->second; auto const size = top - fork; // The fork is at the top of the chain, nothing to pop. if (size == 0) { - handler(error::success); - return; + co_return out_blocks; } // If the fork is at the top there is one block to pop, and so on. @@ -362,11 +473,8 @@ void data_base::pop_above(block_const_ptr_list_ptr out_blocks, hash_digest const for (size_t height = top; height > fork; --height) { domain::message::block next; - // TODO(legacy): parallelize pop of transactions within each block. if ( ! pop(next)) { - //**--** - handler(error::database_insert_failed); - return; + co_return std::unexpected(error::database_insert_failed); } KTH_ASSERT(next.is_valid()); @@ -374,7 +482,7 @@ void data_base::pop_above(block_const_ptr_list_ptr out_blocks, hash_digest const out_blocks->insert(out_blocks->begin(), block); } - handler(error::success); + co_return out_blocks; } code data_base::prune_reorg() { @@ -385,38 +493,31 @@ code data_base::prune_reorg() { } return error::success; } -#endif // ! defined(KTH_DB_READONLY) - -#if ! defined(KTH_DB_READONLY) -// This is designed for write exclusivity and read concurrency. -void data_base::reorganize(infrastructure::config::checkpoint const& fork_point, block_const_ptr_list_const_ptr incoming_blocks, block_const_ptr_list_ptr outgoing_blocks, dispatcher& dispatch, result_handler handler) { - auto const next_height = *safe_add(fork_point.height(), size_t(1)); - // TODO: remove std::bind, use lambda instead. - // TOOD: Even better use C++20 coroutines. - result_handler const pop_handler = std::bind(&data_base::handle_pop, this, _1, incoming_blocks, next_height, std::ref(dispatch), handler); - pop_above(outgoing_blocks, fork_point.hash(), dispatch, pop_handler); -} -void data_base::handle_pop(code const& ec, block_const_ptr_list_const_ptr incoming_blocks, size_t first_height, dispatcher& dispatch, result_handler handler) { - result_handler const push_handler = std::bind(&data_base::handle_push, this, _1, handler); - - if (ec) { - push_handler(ec); - return; +// Invoke pop_above and then push_all. +// Returns the outgoing blocks that were popped. +awaitable_expected data_base::reorganize( + executor_type executor, + infrastructure::config::checkpoint const& fork_point, + block_const_ptr_list_const_ptr incoming_blocks) { + + // Pop blocks above the fork point. + auto pop_result = co_await pop_above(executor, fork_point.hash()); + if ( ! pop_result.has_value()) { + co_return std::unexpected(pop_result.error()); } - push_all(incoming_blocks, first_height, std::ref(dispatch), push_handler); -} + auto outgoing_blocks = std::move(pop_result.value()); -// We never invoke the caller's handler under the mutex, we never fail to clear -// the mutex, and we always invoke the caller's handler exactly once. -void data_base::handle_push(code const& ec, result_handler handler) const { - if (ec) { - handler(ec); - return; + // Push incoming blocks. + auto const next_height = *safe_add(fork_point.height(), size_t(1)); + auto const push_ec = co_await push_all(executor, incoming_blocks, next_height); + if (push_ec) { + co_return std::unexpected(push_ec); } - handler(error::success); + + co_return outgoing_blocks; } #endif // ! defined(KTH_DB_READONLY) -} // namespace kth::database \ No newline at end of file +} // namespace kth::database diff --git a/src/database/src/databases/header_abla_entry.cpp b/src/database/src/databases/header_abla_entry.cpp index 59d1bfea..b8730ac2 100644 --- a/src/database/src/databases/header_abla_entry.cpp +++ b/src/database/src/databases/header_abla_entry.cpp @@ -27,6 +27,30 @@ void to_data_with_abla_state(std::ostream& stream, domain::chain::block const& b to_data_with_abla_state(sink, block); } +data_chunk to_data_header_only(domain::chain::header const& header) { + data_chunk data; + auto const size = header.serialized_size(true) + 8 + 8 + 8; + data.reserve(size); + data_sink ostream(data); + ostream_writer sink(ostream); + to_data_header_only(sink, header); + ostream.flush(); + KTH_ASSERT(data.size() == size); + return data; +} + +data_chunk to_data_header_with_abla_state(domain::chain::header const& header, uint64_t block_size, uint64_t control_block_size, uint64_t elastic_buffer_size) { + data_chunk data; + auto const size = header.serialized_size(true) + 8 + 8 + 8; + data.reserve(size); + data_sink ostream(data); + ostream_writer sink(ostream); + to_data_header_with_abla_state(sink, header, block_size, control_block_size, elastic_buffer_size); + ostream.flush(); + KTH_ASSERT(data.size() == size); + return data; +} + expect get_header_and_abla_state_from_data(byte_reader& reader) { auto header = domain::chain::header::from_data(reader, true); if ( ! header) { diff --git a/src/database/src/settings.cpp b/src/database/src/settings.cpp index 552dcfd2..aa1424ad 100644 --- a/src/database/src/settings.cpp +++ b/src/database/src/settings.cpp @@ -43,6 +43,7 @@ settings::settings() , db_max_size(get_db_max_size_mainnet(db_mode)) , safe_mode(true) , cache_capacity(0) + , parallel_block_push(true) // default to parallel (original behavior) {} settings::settings(domain::config::network context) diff --git a/src/database/test/data_base.cpp b/src/database/test/data_base.cpp index 704c5064..eb13d7e2 100644 --- a/src/database/test/data_base.cpp +++ b/src/database/test/data_base.cpp @@ -4,12 +4,18 @@ #include +#include #include #include #include #include +#include +#include +#include +#include + using namespace kth::domain::chain; using namespace kth::database; using namespace kth::domain::wallet; @@ -66,33 +72,29 @@ class data_base_accessor : public data_base { data_base_accessor(settings const& settings) : data_base(settings) {} - void push_all(block_const_ptr_list_const_ptr in_blocks, size_t first_height, dispatcher& dispatch, result_handler handler) { - data_base::push_all(in_blocks, first_height, dispatch, handler); + asio::awaitable push_all(executor_type executor, block_const_ptr_list_const_ptr in_blocks, size_t first_height) { + return data_base::push_all(executor, in_blocks, first_height); } - void pop_above(block_const_ptr_list_ptr out_blocks, hash_digest const& fork_hash, dispatcher& dispatch, result_handler handler) { - data_base::pop_above(out_blocks, fork_hash, dispatch, handler); + asio::awaitable pop_above(executor_type executor, hash_digest const& fork_hash) { + return data_base::pop_above(executor, fork_hash); } }; static -code push_all_result(data_base_accessor& instance, block_const_ptr_list_const_ptr in_blocks, size_t first_height, dispatcher& dispatch) { - std::promise promise; - auto const handler = [&promise](code ec) { - promise.set_value(ec); - }; - instance.push_all(in_blocks, first_height, dispatch, handler); - return promise.get_future().get(); +code push_all_result(data_base_accessor& instance, block_const_ptr_list_const_ptr in_blocks, size_t first_height, asio::thread_pool& pool) { + auto future = asio::co_spawn(pool.get_executor(), + instance.push_all(pool.get_executor(), in_blocks, first_height), + asio::use_future); + return future.get(); } static -code pop_above_result(data_base_accessor& instance, block_const_ptr_list_ptr out_blocks, hash_digest const& fork_hash, dispatcher& dispatch) { - std::promise promise; - auto const handler = [&promise](code ec) { - promise.set_value(ec); - }; - instance.pop_above(out_blocks, fork_hash, dispatch, handler); - return promise.get_future().get(); +std::expected pop_above_result(data_base_accessor& instance, hash_digest const& fork_hash, asio::thread_pool& pool) { + auto future = asio::co_spawn(pool.get_executor(), + instance.pop_above(pool.get_executor(), fork_hash), + asio::use_future); + return future.get(); } // End Test Suite diff --git a/src/domain/CMakeLists.txt b/src/domain/CMakeLists.txt index 3635148d..879de9ed 100644 --- a/src/domain/CMakeLists.txt +++ b/src/domain/CMakeLists.txt @@ -28,7 +28,7 @@ if (KTH_WITH_QRENCODE) add_definitions(-DKTH_WITH_QRENCODE) endif() -add_definitions(-DJEMALLOC) +# JEMALLOC is now configured in the main CMakeLists.txt via conan if (JUST_KTH_SOURCES) @@ -87,17 +87,11 @@ if (WITH_ICU) endif() find_package(tiny-aes-c REQUIRED) -# # jemalloc -# find_package(PkgConfig REQUIRED) -# pkg_check_modules(JEMALLOC jemalloc) -# message("-- Found jemalloc: JEMALLOC_INCLUDE_DIRS: ${JEMALLOC_INCLUDE_DIRS}") -# message("-- Found jemalloc: JEMALLOC_LIBRARY_DIRS: ${JEMALLOC_LIBRARY_DIRS}") -# message("-- Found jemalloc: JEMALLOC_CFLAGS_OTHER: ${JEMALLOC_CFLAGS_OTHER}") - -# include_directories(${JEMALLOC_INCLUDE_DIRS}) -# link_directories(${JEMALLOC_LIBRARY_DIRS}) -# add_definitions(${JEMALLOC_CFLAGS_OTHER}) +# jemalloc is now configured in the main CMakeLists.txt via conan +if (KTH_WITH_JEMALLOC) + find_package(jemalloc REQUIRED) +endif() @@ -466,7 +460,9 @@ endif() target_link_libraries(${PROJECT_NAME} PUBLIC infrastructure::infrastructure) target_link_libraries(${PROJECT_NAME} PUBLIC tiny-aes-c::tiny-aes-c) -target_link_libraries(${PROJECT_NAME} PUBLIC ${JEMALLOC_LIBRARIES}) +if(KTH_WITH_JEMALLOC) + target_link_libraries(${PROJECT_NAME} PUBLIC jemalloc::jemalloc) +endif() if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") target_link_libraries(${PROJECT_NAME} PUBLIC Boost::thread) diff --git a/src/domain/conanfile.py b/src/domain/conanfile.py deleted file mode 100644 index fb97546b..00000000 --- a/src/domain/conanfile.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, cmake_layout -from kthbuild import option_on_off -from kthbuild import KnuthConanFileV2 - -required_conan_version = ">=2.0" - -class KnuthDomainConan(KnuthConanFileV2): - name = "domain" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/domain" - description = "Crypto Cross-Platform C++ Development Toolkit" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = {"shared": [True, False], - "fPIC": [True, False], - "with_icu": [True, False], - "with_qrencode": [True, False], - "tests": [True, False], - "examples": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - - "verbose": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - "disable_get_blocks": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "with_icu": False, - "with_qrencode": False, - "tests": True, - "examples": False, - "currency": "BCH", - - "march_strategy": "download_if_possible", - - "verbose": False, - "cmake_export_compile_commands": False, - "disable_get_blocks": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "include/*", "test/*", "examples/*" - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def requirements(self): - self.requires("infrastructure/0.43.0", transitive_headers=True, transitive_libs=True) - self.requires("tiny-aes-c/1.0.0", transitive_headers=True, transitive_libs=True) - - if self.options.currency == "LTC": - self.requires("OpenSSL/1.0.2l@conan/stable", transitive_headers=True, transitive_libs=True) - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - def package_id(self): - KnuthConanFileV2.package_id(self) - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - tc.variables["WITH_ICU"] = option_on_off(self.options.with_icu) - tc.variables["KTH_WITH_QRENCODE"] = option_on_off(self.options.with_qrencode) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - - if not self.options.cmake_export_compile_commands: - cmake.build() - #Note: Cmake Tests and Visual Studio doesn't work - if self.options.tests: - cmake.test() - # cmake.test(target="tests") - - def package(self): - cmake = CMake(self) - cmake.install() - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["domain"] - - if self.settings.os == "Linux" or self.settings.os == "FreeBSD" or self.settings.os == "Emscripten": - self.cpp_info.system_libs.append("pthread") - - if self.settings.os == "Windows" and self.settings.compiler == "gcc": # MinGW - self.cpp_info.system_libs.append("ws2_32") - self.cpp_info.system_libs.append("wsock32") - - if not self.is_shared: - self.cpp_info.defines.append("KD_STATIC") - - diff --git a/src/infrastructure/CMakeLists.txt b/src/infrastructure/CMakeLists.txt index cf503570..69f28e0f 100644 --- a/src/infrastructure/CMakeLists.txt +++ b/src/infrastructure/CMakeLists.txt @@ -89,6 +89,13 @@ if (KTH_ASIO_STANDALONE) find_package(asio REQUIRED) endif() +# jemalloc support for memory tracking +option(KTH_WITH_JEMALLOC "Use jemalloc for memory allocation" OFF) +if (KTH_WITH_JEMALLOC) + find_package(jemalloc REQUIRED) + add_definitions(-DKTH_WITH_JEMALLOC) +endif() + include(CheckCXXCompilerFlag) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/ci_utils/cmake) @@ -212,7 +219,6 @@ set(kth_sources_just_legacy src/utility/binary.cpp src/utility/conditional_lock.cpp - src/utility/dispatcher.cpp src/utility/flush_lock.cpp src/utility/interprocess_lock.cpp src/utility/monitor.cpp @@ -222,6 +228,7 @@ set(kth_sources_just_legacy src/utility/sequential_lock.cpp src/utility/string.cpp + src/utility/system_memory.cpp src/utility/thread.cpp src/wallet/dictionary.cpp @@ -233,6 +240,9 @@ set(kth_sources_just_legacy src/wallet/uri.cpp src/utility/pseudo_random.cpp + + # DEPRECATED - kept for backward compatibility during migration (see asio.md) + include/kth/infrastructure/deprecated/utility/dispatcher.cpp ) if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") @@ -243,12 +253,13 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") src/config/printer.cpp src/utility/deadline.cpp - src/utility/sequencer.cpp src/utility/socket.cpp src/utility/pseudo_random_broken_do_not_use.cpp - src/utility/work.cpp + # DEPRECATED - kept for backward compatibility during migration (see asio.md) + include/kth/infrastructure/deprecated/utility/sequencer.cpp + include/kth/infrastructure/deprecated/utility/work.cpp ) endif() @@ -341,9 +352,7 @@ set(kth_headers include/kth/infrastructure/impl/utility/data.ipp include/kth/infrastructure/impl/utility/ostream_writer.ipp include/kth/infrastructure/impl/utility/pending.ipp - include/kth/infrastructure/impl/utility/resubscriber.ipp include/kth/infrastructure/impl/utility/serializer.ipp - include/kth/infrastructure/impl/utility/subscriber.ipp include/kth/infrastructure/impl/utility/string.ipp include/kth/infrastructure/impl/utility/track.ipp @@ -370,8 +379,6 @@ set(kth_headers include/kth/infrastructure/utility/data.hpp include/kth/infrastructure/utility/deadline.hpp include/kth/infrastructure/utility/decorator.hpp - include/kth/infrastructure/utility/delegates.hpp - include/kth/infrastructure/utility/dispatcher.hpp include/kth/infrastructure/utility/enable_shared_from_base.hpp include/kth/infrastructure/utility/endian.hpp include/kth/infrastructure/utility/exceptions.hpp @@ -387,20 +394,16 @@ set(kth_headers include/kth/infrastructure/utility/pseudo_random_broken_do_not_use.hpp include/kth/infrastructure/utility/reader.hpp - include/kth/infrastructure/utility/resubscriber.hpp include/kth/infrastructure/utility/scope_lock.hpp - include/kth/infrastructure/utility/sequencer.hpp include/kth/infrastructure/utility/sequential_lock.hpp include/kth/infrastructure/utility/serializer.hpp include/kth/infrastructure/utility/socket.hpp include/kth/infrastructure/utility/string.hpp - include/kth/infrastructure/utility/subscriber.hpp - include/kth/infrastructure/utility/synchronizer.hpp + include/kth/infrastructure/utility/system_memory.hpp include/kth/infrastructure/utility/thread.hpp include/kth/infrastructure/utility/threadpool.hpp include/kth/infrastructure/utility/timer.hpp include/kth/infrastructure/utility/track.hpp - include/kth/infrastructure/utility/work.hpp include/kth/infrastructure/utility/writer.hpp include/kth/infrastructure/utility/async_channel.hpp include/kth/infrastructure/utility/awaitable_helpers.hpp @@ -415,6 +418,17 @@ set(kth_headers include/kth/infrastructure/wallet/uri.hpp include/kth/infrastructure.hpp + + # DEPRECATED - moved to deprecated/ folder (see asio.md) + # deprecated/impl/utility/resubscriber.ipp + # deprecated/impl/utility/subscriber.ipp + # deprecated/utility/delegates.hpp + # deprecated/utility/dispatcher.hpp + # deprecated/utility/resubscriber.hpp + # deprecated/utility/sequencer.hpp + # deprecated/utility/subscriber.hpp + # deprecated/utility/synchronizer.hpp + # deprecated/utility/work.hpp ) if (KTH_WITH_PNG) @@ -622,6 +636,10 @@ if (KTH_ASIO_STANDALONE) target_link_libraries(${PROJECT_NAME} PUBLIC asio::asio) endif() +if (KTH_WITH_JEMALLOC) + target_link_libraries(${PROJECT_NAME} PUBLIC jemalloc::jemalloc) +endif() + target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_THREAD_LIBS_INIT}) if (MINGW) diff --git a/src/infrastructure/conanfile.py b/src/infrastructure/conanfile.py deleted file mode 100644 index 7b558481..00000000 --- a/src/infrastructure/conanfile.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, cmake_layout -from conan.tools.files import copy -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" - -class KnuthInfrastructureConan(KnuthConanFileV2): - name = "infrastructure" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/knuth/infrastructure" - description = "Multicrypto Cross-Platform C++ Development Toolkit" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = { - "shared": [True, False], - "fPIC": [True, False], - "with_icu": [True, False], - "with_png": [True, False], - "with_qrencode": [True, False], - "tests": [True, False], - "examples": [True, False], - - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - - "verbose": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - "asio_standalone": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "with_icu": False, - "with_png": False, - "with_qrencode": False, - "tests": True, - "examples": False, - - "march_strategy": "download_if_possible", - - "verbose": False, - "cmake_export_compile_commands": False, - "asio_standalone": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "include/*", "test/*", "examples/*" - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def requirements(self): - self.requires("secp256k1/0.22.0", transitive_headers=True, transitive_libs=True) - self.requires("boost/1.89.0", transitive_headers=True, transitive_libs=True) - self.requires("fmt/11.1.3", transitive_headers=True, transitive_libs=True) - self.requires("expected-lite/0.8.0", transitive_headers=True, transitive_libs=True) - self.requires("ctre/3.9.0", transitive_headers=True, transitive_libs=True) - - self.requires("spdlog/1.15.1", transitive_headers=True, transitive_libs=True) - - if self.options.with_png: - self.requires("libpng/1.6.51", transitive_headers=True, transitive_libs=True) - - if self.options.with_qrencode: - self.requires("libqrencode/4.1.1", transitive_headers=True, transitive_libs=True) - - if self.options.asio_standalone: - self.requires("asio/1.28.1", transitive_headers=True, transitive_libs=True) - - if self.options.with_icu: - self.requires("icu/76.1", transitive_headers=True, transitive_libs=True) - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - # self.output.info("libcxx: %s" % (str(self.settings.compiler.libcxx),)) - KnuthConanFileV2.configure(self) - - self.options["fmt/*"].header_only = True - - if self.settings.os == "Emscripten": - self.options["boost/*"].header_only = True - - self.options["spdlog/*"].header_only = True - - def package_id(self): - KnuthConanFileV2.package_id(self) - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - tc.variables["WITH_ICU"] = option_on_off(self.options.with_icu) - tc.variables["KTH_WITH_QRENCODE"] = option_on_off(self.options.with_qrencode) - tc.variables["KTH_WITH_PNG"] = option_on_off(self.options.with_png) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - - if not self.options.cmake_export_compile_commands: - cmake.build() - #Note: Cmake Tests and Visual Studio doesn't work - if self.options.tests: - cmake.test() - # cmake.test(target="tests") - - # def imports(self): - # self.copy("*.h", "", "include") - - def package(self): - cmake = CMake(self) - cmake.install() - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["infrastructure"] - ... - # self.cpp_info.requires = ["boost::program_options", - # "boost::thread", - # "secp256k1::secp256k1", - # "spdlog::spdlog", - # "fmt::fmt", - # "expected-lite::expected-lite", - # "ctre::ctre" - # ] - - self.cpp_info.requires = ["secp256k1::secp256k1", - "spdlog::spdlog", - "fmt::fmt", - "expected-lite::expected-lite", - "ctre::ctre" - ] - - if self.settings.os != "Emscripten": - self.cpp_info.requires.append("boost::program_options") - self.cpp_info.requires.append("boost::thread") - else: - self.cpp_info.requires.append("boost::boost") - - if self.options.with_png: - self.cpp_info.requires.append("libpng::libpng") - if self.options.with_qrencode: - self.cpp_info.requires.append("libqrencode::libqrencode") - - - if self.settings.os == "Linux" or self.settings.os == "FreeBSD" or self.settings.os == "Emscripten": - self.cpp_info.system_libs.append("pthread") - - if self.settings.os == "Linux" and self.settings.compiler == "gcc" and float(str(self.settings.compiler.version)) <= 8: - self.cpp_info.system_libs.append("stdc++fs") - - if self.settings.os == "Windows" and self.settings.compiler == "gcc": # MinGW - self.cpp_info.system_libs.append("ws2_32") - self.cpp_info.system_libs.append("wsock32") - - if not self.is_shared: - self.cpp_info.defines.append("KI_STATIC") - - if self.options.with_png: - self.cpp_info.defines.append("KTH_WITH_PNG") - if self.options.with_qrencode: - self.cpp_info.defines.append("KTH_WITH_QRENCODE") - diff --git a/src/infrastructure/include/kth/infrastructure.hpp b/src/infrastructure/include/kth/infrastructure.hpp index 8935a92d..17ffb776 100644 --- a/src/infrastructure/include/kth/infrastructure.hpp +++ b/src/infrastructure/include/kth/infrastructure.hpp @@ -82,8 +82,6 @@ #include #include #include - -#include #include #include #include @@ -99,27 +97,21 @@ #endif #include - #include #include - #include -#include #include -#include #include #include #include #include - -#include +#include #include #include #include #include #include #include - #include #include @@ -135,14 +127,20 @@ #endif #if ! defined(__EMSCRIPTEN__) - #include #include - -#include #include -#include -#include #endif +// ============================================================================= +// DEPRECATED - moved to deprecated/ folder (see doc/asio.md) +// ============================================================================= +// #include +// #include +// #include +// #include +// #include +// #include +// #include + #endif /*KTH_INFRASTRUCTURE_INFRASTRUCTURE_HPP_*/ diff --git a/src/infrastructure/include/kth/infrastructure/impl/utility/resubscriber.ipp b/src/infrastructure/include/kth/infrastructure/deprecated/impl/utility/resubscriber.ipp similarity index 91% rename from src/infrastructure/include/kth/infrastructure/impl/utility/resubscriber.ipp rename to src/infrastructure/include/kth/infrastructure/deprecated/impl/utility/resubscriber.ipp index ab54ca20..bf1e9008 100644 --- a/src/infrastructure/include/kth/infrastructure/impl/utility/resubscriber.ipp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/impl/utility/resubscriber.ipp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_RESUBSCRIBER_IPP #define KTH_INFRASTRUCTURE_RESUBSCRIBER_IPP @@ -11,9 +21,8 @@ #include #include -#include +#include #include -#include ////#include namespace kth { diff --git a/src/infrastructure/include/kth/infrastructure/impl/utility/subscriber.ipp b/src/infrastructure/include/kth/infrastructure/deprecated/impl/utility/subscriber.ipp similarity index 87% rename from src/infrastructure/include/kth/infrastructure/impl/utility/subscriber.ipp rename to src/infrastructure/include/kth/infrastructure/deprecated/impl/utility/subscriber.ipp index 3d683dcf..8f7c84ac 100644 --- a/src/infrastructure/include/kth/infrastructure/impl/utility/subscriber.ipp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/impl/utility/subscriber.ipp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_SUBSCRIBER_IPP #define KTH_INFRASTRUCTURE_SUBSCRIBER_IPP @@ -11,9 +21,8 @@ #include #include -#include +#include #include -#include ////#include namespace kth { diff --git a/src/infrastructure/include/kth/infrastructure/utility/delegates.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/delegates.hpp similarity index 75% rename from src/infrastructure/include/kth/infrastructure/utility/delegates.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/delegates.hpp index 23831e93..4628b233 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/delegates.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/delegates.hpp @@ -2,13 +2,23 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_DELEGATES_HPP #define KTH_INFRASTRUCTURE_DELEGATES_HPP #include #if ! defined(__EMSCRIPTEN__) -#include +#include #endif namespace kth { diff --git a/src/infrastructure/src/utility/dispatcher.cpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/dispatcher.cpp similarity index 59% rename from src/infrastructure/src/utility/dispatcher.cpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/dispatcher.cpp index b2edaef9..4896e161 100644 --- a/src/infrastructure/src/utility/dispatcher.cpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/dispatcher.cpp @@ -2,15 +2,24 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + +#include #include #include #if ! defined(__EMSCRIPTEN__) -#include -#include +#include #endif // ! defined(__EMSCRIPTEN__) diff --git a/src/infrastructure/include/kth/infrastructure/utility/dispatcher.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/dispatcher.hpp similarity index 90% rename from src/infrastructure/include/kth/infrastructure/utility/dispatcher.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/dispatcher.hpp index 4cb0d52f..7d584625 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/dispatcher.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/dispatcher.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_DISPATCHER_HPP #define KTH_INFRASTRUCTURE_DISPATCHER_HPP @@ -12,7 +22,6 @@ #include #include -#include #if ! defined(__EMSCRIPTEN__) @@ -20,9 +29,10 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include #endif // ! defined(__EMSCRIPTEN__) @@ -205,9 +215,9 @@ class KI_API dispatcher : noncopyable { //// sequence(BIND_ELEMENT(args, element, call)); ////} - /// The size of the dispatcher's threadpool at the time of calling. - inline - size_t size() const { + /// The size of the dispatcher's threadpool. + [[nodiscard]] + size_t size() const noexcept { return pool_.size(); } @@ -232,11 +242,6 @@ class KI_API dispatcher : noncopyable { void ordered(Args&&... args) { std::invoke(std::forward(args)...); } - - inline - size_t size() const { - return 1; - } }; #endif // ! defined(__EMSCRIPTEN__) diff --git a/src/infrastructure/include/kth/infrastructure/utility/resubscriber.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/resubscriber.hpp similarity index 72% rename from src/infrastructure/include/kth/infrastructure/utility/resubscriber.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/resubscriber.hpp index 66cd0259..918b7720 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/resubscriber.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/resubscriber.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_RESUBSCRIBER_HPP #define KTH_INFRASTRUCTURE_RESUBSCRIBER_HPP @@ -10,10 +20,9 @@ #include #include -#include +#include #include #include -#include ////#include namespace kth { @@ -66,6 +75,6 @@ class resubscriber } // namespace kth -#include +#include #endif diff --git a/src/infrastructure/src/utility/sequencer.cpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/sequencer.cpp similarity index 73% rename from src/infrastructure/src/utility/sequencer.cpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/sequencer.cpp index aa406168..4ace145f 100644 --- a/src/infrastructure/src/utility/sequencer.cpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/sequencer.cpp @@ -2,7 +2,17 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + +#include #include diff --git a/src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/sequencer.hpp similarity index 66% rename from src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/sequencer.hpp index 85abcaf4..b400d4e4 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/sequencer.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/sequencer.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_SEQUENCER_HPP #define KTH_INFRASTRUCTURE_SEQUENCER_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/subscriber.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/subscriber.hpp similarity index 69% rename from src/infrastructure/include/kth/infrastructure/utility/subscriber.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/subscriber.hpp index 8925b995..49a4e9ba 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/subscriber.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/subscriber.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_SUBSCRIBER_HPP #define KTH_INFRASTRUCTURE_SUBSCRIBER_HPP @@ -10,10 +20,9 @@ #include #include -#include +#include #include #include -#include ////#include namespace kth { @@ -59,6 +68,6 @@ class subscriber } // namespace kth -#include +#include #endif diff --git a/src/infrastructure/include/kth/infrastructure/utility/synchronizer.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/synchronizer.hpp similarity index 89% rename from src/infrastructure/include/kth/infrastructure/utility/synchronizer.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/synchronizer.hpp index 43b1949d..54f0c368 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/synchronizer.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/synchronizer.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_SYNCHRONIZER_HPP #define KTH_INFRASTRUCTURE_SYNCHRONIZER_HPP diff --git a/src/infrastructure/include/kth/infrastructure/deprecated/utility/work.cpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/work.cpp new file mode 100644 index 00000000..b32f8fe5 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/work.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + +#include + +#include +#include +#include + + +namespace kth { + +work::work(threadpool& pool, std::string const& name) + : name_(name) + , executor_(pool.executor()) + , strand_(::asio::make_strand(executor_)) + , sequence_(executor_) +{} + +} // namespace kth diff --git a/src/infrastructure/include/kth/infrastructure/utility/work.hpp b/src/infrastructure/include/kth/infrastructure/deprecated/utility/work.hpp similarity index 84% rename from src/infrastructure/include/kth/infrastructure/utility/work.hpp rename to src/infrastructure/include/kth/infrastructure/deprecated/utility/work.hpp index 9a3e06b8..5a0a6ebd 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/work.hpp +++ b/src/infrastructure/include/kth/infrastructure/deprecated/utility/work.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_INFRASTRUCTURE_WORK_HPP #define KTH_INFRASTRUCTURE_WORK_HPP @@ -15,7 +25,7 @@ #include #include #include -#include +#include #include namespace kth { diff --git a/src/infrastructure/include/kth/infrastructure/display_mode.hpp b/src/infrastructure/include/kth/infrastructure/display_mode.hpp new file mode 100644 index 00000000..4adfd6b8 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/display_mode.hpp @@ -0,0 +1,47 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_DISPLAY_MODE_HPP +#define KTH_INFRASTRUCTURE_DISPLAY_MODE_HPP + +#include +#include +#include + +namespace kth { + +/// Display mode for the node executable +/// Controls how output is shown to the user +enum class display_mode : uint8_t { + /// TUI dashboard with real-time status + tui = 0, + + /// Traditional scrolling log output (default) + log = 1, + + /// Daemon mode - minimal console output (for systemd/background) + daemon = 2 +}; + +/// Convert display_mode to string +constexpr std::string_view to_string(display_mode mode) noexcept { + switch (mode) { + case display_mode::tui: return "tui"; + case display_mode::log: return "log"; + case display_mode::daemon: return "daemon"; + default: return "unknown"; + } +} + +/// Parse display_mode from string +inline display_mode parse_display_mode(std::string_view str) noexcept { + if (str == "tui" || str == "TUI") return display_mode::tui; + if (str == "log" || str == "LOG") return display_mode::log; + if (str == "daemon" || str == "DAEMON") return display_mode::daemon; + return display_mode::log; // default +} + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_DISPLAY_MODE_HPP diff --git a/src/infrastructure/include/kth/infrastructure/handlers.hpp b/src/infrastructure/include/kth/infrastructure/handlers.hpp index a8b82acf..68ba3eb7 100644 --- a/src/infrastructure/include/kth/infrastructure/handlers.hpp +++ b/src/infrastructure/include/kth/infrastructure/handlers.hpp @@ -5,10 +5,13 @@ #ifndef KTH_INFRASTRUCTURE_HANDLERS_HPP #define KTH_INFRASTRUCTURE_HANDLERS_HPP +#include #include #include +#include + namespace kth { using handle0 = std::function; @@ -22,6 +25,9 @@ using handle2 = std::function; template using handle3 = std::function; +template +using awaitable_expected = ::asio::awaitable>; + } // namespace kth #endif diff --git a/src/infrastructure/include/kth/infrastructure/log/statsd_sink.hpp b/src/infrastructure/include/kth/infrastructure/log/statsd_sink.hpp index dba9e2e1..378db5cd 100644 --- a/src/infrastructure/include/kth/infrastructure/log/statsd_sink.hpp +++ b/src/infrastructure/include/kth/infrastructure/log/statsd_sink.hpp @@ -10,7 +10,6 @@ #include #include #include -#include namespace kth::log { diff --git a/src/infrastructure/include/kth/infrastructure/message/network_address.hpp b/src/infrastructure/include/kth/infrastructure/message/network_address.hpp index 60945640..aeb18683 100644 --- a/src/infrastructure/include/kth/infrastructure/message/network_address.hpp +++ b/src/infrastructure/include/kth/infrastructure/message/network_address.hpp @@ -76,6 +76,7 @@ struct KI_API network_address { } bool is_valid() const; + bool is_routable() const; void reset(); static diff --git a/src/infrastructure/include/kth/infrastructure/utility/broadcaster.hpp b/src/infrastructure/include/kth/infrastructure/utility/broadcaster.hpp new file mode 100644 index 00000000..053f7360 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/broadcaster.hpp @@ -0,0 +1,174 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_BROADCASTER_HPP +#define KTH_INFRASTRUCTURE_BROADCASTER_HPP + +#include +#include +#include +#include + +#include +#include +#include + +namespace kth { + +/// Thread-safe broadcaster for pub/sub pattern using Asio channels. +/// Replaces the deprecated resubscriber class. +/// +/// Usage: +/// broadcaster bc(executor); +/// +/// // Subscribe (returns a channel to receive from) +/// auto channel = bc.subscribe(); +/// +/// // In a coroutine, receive events: +/// while (auto event = co_await channel->async_receive(asio::use_awaitable)) { +/// auto [ec, height, block] = *event; +/// // process... +/// } +/// +/// // Publish to all subscribers: +/// bc.publish(error::success, height, block); +/// +template +class broadcaster { +public: + using executor_type = ::asio::any_io_executor; + using channel_type = ::asio::experimental::concurrent_channel; + using channel_ptr = std::shared_ptr; + + static constexpr size_t default_buffer_size = 64; + + explicit broadcaster(executor_type executor, size_t buffer_size = default_buffer_size) + : executor_(std::move(executor)) + , buffer_size_(buffer_size) + , stopped_(false) + {} + + ~broadcaster() { + close(); + } + + // Non-copyable, non-movable + broadcaster(broadcaster const&) = delete; + broadcaster& operator=(broadcaster const&) = delete; + broadcaster(broadcaster&&) = delete; + broadcaster& operator=(broadcaster&&) = delete; + + /// Start accepting subscriptions. + void start() { + stopped_ = false; + } + + /// Stop and close all channels. + void stop() { + close(); + } + + /// Subscribe and get a channel to receive events. + /// Returns nullptr if the broadcaster is stopped. + [[nodiscard]] + channel_ptr subscribe() { + if (stopped_) { + return nullptr; + } + + auto channel = std::make_shared(executor_, buffer_size_); + + { + std::lock_guard lock(mutex_); + subscribers_.push_back(channel); + } + + return channel; + } + + /// Unsubscribe a specific channel. + void unsubscribe(channel_ptr const& channel) { + if ( ! channel) { + return; + } + + std::lock_guard lock(mutex_); + + // Close the channel + channel->close(); + + // Remove from subscribers list + subscribers_.erase( + std::remove_if(subscribers_.begin(), subscribers_.end(), + [&channel](channel_ptr const& ch) { + return ch == channel || ch->is_open() == false; + }), + subscribers_.end() + ); + } + + /// Publish an event to all subscribers. + /// Subscribers that are full or closed are removed. + void publish(Args... args) { + if (stopped_) { + return; + } + + std::lock_guard lock(mutex_); + + // Remove closed channels and try to send to open ones + subscribers_.erase( + std::remove_if(subscribers_.begin(), subscribers_.end(), + [&](channel_ptr& channel) { + if ( ! channel || ! channel->is_open()) { + return true; // Remove closed channels + } + + // try_send is non-blocking, returns false if channel is full + // We use it to avoid blocking the publisher + channel->try_send(std::error_code{}, args...); + return false; + }), + subscribers_.end() + ); + } + + /// Close all subscriber channels. + void close() { + stopped_ = true; + + std::lock_guard lock(mutex_); + + for (auto& channel : subscribers_) { + if (channel && channel->is_open()) { + channel->close(); + } + } + subscribers_.clear(); + } + + /// Number of active subscribers. + [[nodiscard]] + size_t subscriber_count() const { + std::lock_guard lock(mutex_); + return subscribers_.size(); + } + + /// Check if stopped. + [[nodiscard]] + bool stopped() const { + return stopped_; + } + +private: + executor_type executor_; + size_t buffer_size_; + std::atomic stopped_; + mutable std::mutex mutex_; + std::vector subscribers_; +}; + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_BROADCASTER_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/deadline.hpp b/src/infrastructure/include/kth/infrastructure/utility/deadline.hpp index 9b6399bf..dba5937b 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/deadline.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/deadline.hpp @@ -14,10 +14,7 @@ #include #include #include - -#if ! defined(__EMSCRIPTEN__) #include -#endif ////#include diff --git a/src/infrastructure/include/kth/infrastructure/utility/system_memory.hpp b/src/infrastructure/include/kth/infrastructure/utility/system_memory.hpp new file mode 100644 index 00000000..88576305 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/system_memory.hpp @@ -0,0 +1,51 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_UTILITY_SYSTEM_MEMORY_HPP +#define KTH_INFRASTRUCTURE_UTILITY_SYSTEM_MEMORY_HPP + +#include +#include + +#include + +namespace kth { + +/// Get total physical memory in the system (bytes). +/// Returns 0 on unsupported platforms or error. +[[nodiscard]] +KI_API size_t get_total_system_memory(); + +/// Get available (free + reclaimable) memory in the system (bytes). +/// On macOS: free + inactive + purgeable pages. +/// On Linux: MemAvailable from /proc/meminfo. +/// Returns 0 on unsupported platforms or error. +[[nodiscard]] +KI_API size_t get_available_system_memory(); + +/// Get current process memory allocation (bytes). +/// When compiled with jemalloc (KTH_WITH_JEMALLOC), uses jemalloc's +/// stats.allocated for accurate tracking. +/// Otherwise falls back to platform-specific APIs (mach on macOS, +/// /proc/self/statm on Linux). +/// Returns 0 on unsupported platforms or error. +[[nodiscard]] +KI_API size_t get_resident_memory(); + +/// Check if jemalloc is the active memory allocator at runtime. +/// Returns true only if KTH_WITH_JEMALLOC is defined and jemalloc +/// is successfully responding to mallctl queries. +[[nodiscard]] +KI_API bool is_jemalloc_active(); + +/// Get jemalloc version string. +/// Returns the version string if jemalloc is active, +/// "unknown" if active but version query fails, +/// "not compiled" if KTH_WITH_JEMALLOC is not defined. +[[nodiscard]] +KI_API std::string get_jemalloc_version(); + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_UTILITY_SYSTEM_MEMORY_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp b/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp index cf3d6b00..36856f26 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/threadpool.hpp @@ -8,12 +8,13 @@ #include #include -#include +#include namespace kth { +// Wrapper over asio::thread_pool that tracks the thread count. struct threadpool { - explicit + explicit threadpool(size_t num_threads = std::thread::hardware_concurrency()) : num_threads_(num_threads == 0 ? std::thread::hardware_concurrency() : num_threads) , pool_(num_threads_) @@ -27,12 +28,12 @@ struct threadpool { threadpool& operator=(threadpool&&) = delete; [[nodiscard]] - ::asio::thread_pool::executor_type get_executor() { + auto get_executor() { return pool_.get_executor(); } [[nodiscard]] - ::asio::any_io_executor executor() { + auto executor() { return pool_.get_executor(); } @@ -44,11 +45,17 @@ struct threadpool { pool_.join(); } - [[nodiscard]] + [[nodiscard]] size_t size() const noexcept { return num_threads_; } + // Access the underlying asio::thread_pool + [[nodiscard]] + ::asio::thread_pool& get() noexcept { + return pool_; + } + private: size_t num_threads_; ::asio::thread_pool pool_; diff --git a/src/infrastructure/src/log/sink.cpp b/src/infrastructure/src/log/sink.cpp index b5300aa5..8022fc36 100644 --- a/src/infrastructure/src/log/sink.cpp +++ b/src/infrastructure/src/log/sink.cpp @@ -21,13 +21,15 @@ void initialize(std::string const& debug_file, std::string const& error_file, bo if (stdout_enabled) { auto stdout_sink = std::make_shared(); - stdout_sink->set_level(spdlog::level::info); + stdout_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::info); auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink, stdout_sink})); logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + logger->flush_on(spdlog::level::info); spdlog::set_default_logger(logger); } else { auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink})); logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + logger->flush_on(spdlog::level::debug); spdlog::set_default_logger(logger); } diff --git a/src/infrastructure/src/log/statsd_sink.cpp b/src/infrastructure/src/log/statsd_sink.cpp index aa272590..7ece736f 100644 --- a/src/infrastructure/src/log/statsd_sink.cpp +++ b/src/infrastructure/src/log/statsd_sink.cpp @@ -26,7 +26,6 @@ #include #include #include -#include namespace kth::log { diff --git a/src/infrastructure/src/message/network_address.cpp b/src/infrastructure/src/message/network_address.cpp index f03045e9..ed10f6b1 100644 --- a/src/infrastructure/src/message/network_address.cpp +++ b/src/infrastructure/src/message/network_address.cpp @@ -29,6 +29,124 @@ bool network_address::is_valid() const { || (ip_ != null_address); } +namespace { + +// Check if address is IPv4-mapped in IPv6 (::ffff:x.x.x.x) +inline bool is_ipv4_mapped(ip_address const& ip) { + // IPv4-mapped IPv6: 00 00 00 00 00 00 00 00 00 00 FF FF xx xx xx xx + return ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && + ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 && + ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff; +} + +// Get the IPv4 bytes from a mapped address (last 4 bytes) +inline std::array get_ipv4_bytes(ip_address const& ip) { + return {ip[12], ip[13], ip[14], ip[15]}; +} + +// RFC1918: Private IPv4 (10.x.x.x, 172.16-31.x.x, 192.168.x.x) +inline bool is_rfc1918(ip_address const& ip) { + if (!is_ipv4_mapped(ip)) return false; + auto const ipv4 = get_ipv4_bytes(ip); + return ipv4[0] == 10 || + (ipv4[0] == 192 && ipv4[1] == 168) || + (ipv4[0] == 172 && ipv4[1] >= 16 && ipv4[1] <= 31); +} + +// RFC3927: Link-local IPv4 (169.254.x.x) +inline bool is_rfc3927(ip_address const& ip) { + if (!is_ipv4_mapped(ip)) return false; + auto const ipv4 = get_ipv4_bytes(ip); + return ipv4[0] == 169 && ipv4[1] == 254; +} + +// RFC5737: Documentation IPv4 (192.0.2.x, 198.51.100.x, 203.0.113.x) +inline bool is_rfc5737(ip_address const& ip) { + if (!is_ipv4_mapped(ip)) return false; + auto const ipv4 = get_ipv4_bytes(ip); + return (ipv4[0] == 192 && ipv4[1] == 0 && ipv4[2] == 2) || + (ipv4[0] == 198 && ipv4[1] == 51 && ipv4[2] == 100) || + (ipv4[0] == 203 && ipv4[1] == 0 && ipv4[2] == 113); +} + +// RFC6598: Carrier-grade NAT (100.64-127.x.x) +inline bool is_rfc6598(ip_address const& ip) { + if (!is_ipv4_mapped(ip)) return false; + auto const ipv4 = get_ipv4_bytes(ip); + return ipv4[0] == 100 && ipv4[1] >= 64 && ipv4[1] <= 127; +} + +// RFC2544: Benchmarking (198.18.x.x, 198.19.x.x) +inline bool is_rfc2544(ip_address const& ip) { + if (!is_ipv4_mapped(ip)) return false; + auto const ipv4 = get_ipv4_bytes(ip); + return ipv4[0] == 198 && (ipv4[1] == 18 || ipv4[1] == 19); +} + +// IPv4 loopback (127.x.x.x) or unspecified (0.x.x.x) +inline bool is_ipv4_local(ip_address const& ip) { + if (!is_ipv4_mapped(ip)) return false; + auto const ipv4 = get_ipv4_bytes(ip); + return ipv4[0] == 127 || ipv4[0] == 0; +} + +// RFC4862: IPv6 Link-local (FE80::/10) +inline bool is_rfc4862(ip_address const& ip) { + // Pure IPv6 check (not IPv4-mapped) + if (is_ipv4_mapped(ip)) return false; + return ip[0] == 0xfe && (ip[1] & 0xc0) == 0x80; +} + +// RFC4193: IPv6 Unique-local (FC00::/7) +inline bool is_rfc4193(ip_address const& ip) { + if (is_ipv4_mapped(ip)) return false; + return (ip[0] & 0xfe) == 0xfc; +} + +// RFC3849: IPv6 Documentation (2001:DB8::/32) +inline bool is_rfc3849(ip_address const& ip) { + if (is_ipv4_mapped(ip)) return false; + return ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x0d && ip[3] == 0xb8; +} + +// IPv6 loopback (::1) +inline bool is_ipv6_loopback(ip_address const& ip) { + if (is_ipv4_mapped(ip)) return false; + return ip == ip_address{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}; +} + +// IPv6 unspecified (::) +inline bool is_ipv6_unspecified(ip_address const& ip) { + return ip == null_address; +} + +} // anonymous namespace + +bool network_address::is_routable() const { + if (!is_valid()) return false; + if (port_ == 0) return false; + + // Check for non-routable addresses + // IPv4-mapped addresses + if (is_ipv4_mapped(ip_)) { + if (is_rfc1918(ip_)) return false; // Private + if (is_rfc3927(ip_)) return false; // Link-local + if (is_rfc5737(ip_)) return false; // Documentation + if (is_rfc6598(ip_)) return false; // Carrier-grade NAT + if (is_rfc2544(ip_)) return false; // Benchmarking + if (is_ipv4_local(ip_)) return false; // Loopback/unspecified + } else { + // Pure IPv6 + if (is_rfc4862(ip_)) return false; // Link-local + if (is_rfc4193(ip_)) return false; // Unique-local + if (is_rfc3849(ip_)) return false; // Documentation + if (is_ipv6_loopback(ip_)) return false; + if (is_ipv6_unspecified(ip_)) return false; + } + + return true; +} + void network_address::reset() { timestamp_ = 0; services_ = 0; diff --git a/src/infrastructure/src/utility/deadline.cpp b/src/infrastructure/src/utility/deadline.cpp index fab283ec..139e49f8 100644 --- a/src/infrastructure/src/utility/deadline.cpp +++ b/src/infrastructure/src/utility/deadline.cpp @@ -11,7 +11,6 @@ #include #if ! defined(__EMSCRIPTEN__) -#include #endif #include diff --git a/src/infrastructure/src/utility/socket.cpp b/src/infrastructure/src/utility/socket.cpp index 44b4a8d1..aa8dc477 100644 --- a/src/infrastructure/src/utility/socket.cpp +++ b/src/infrastructure/src/utility/socket.cpp @@ -9,7 +9,6 @@ #include #include #include -#include namespace kth { diff --git a/src/infrastructure/src/utility/system_memory.cpp b/src/infrastructure/src/utility/system_memory.cpp new file mode 100644 index 00000000..99ed3e31 --- /dev/null +++ b/src/infrastructure/src/utility/system_memory.cpp @@ -0,0 +1,207 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#if defined(KTH_WITH_JEMALLOC) +#include +#endif + +#if defined(_WIN32) +#include +#include +#elif defined(__APPLE__) +#include +#include +#elif defined(__FreeBSD__) +#include +#include +#include +#include +#elif defined(__linux__) +#include +#include +#include +#endif + +namespace kth { + +size_t get_total_system_memory() { +#if defined(_WIN32) + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + if (GlobalMemoryStatusEx(&status)) { + return static_cast(status.ullTotalPhys); + } + return 0; +#elif defined(__APPLE__) + int mib[2] = {CTL_HW, HW_MEMSIZE}; + uint64_t memsize = 0; + size_t len = sizeof(memsize); + if (sysctl(mib, 2, &memsize, &len, nullptr, 0) == 0) { + return static_cast(memsize); + } + return 0; +#elif defined(__FreeBSD__) + uint64_t memsize = 0; + size_t len = sizeof(memsize); + if (sysctlbyname("hw.physmem", &memsize, &len, nullptr, 0) == 0) { + return static_cast(memsize); + } + return 0; +#elif defined(__linux__) + struct sysinfo info; + if (sysinfo(&info) == 0) { + return info.totalram * info.mem_unit; + } + return 0; +#else + return 0; +#endif +} + +size_t get_available_system_memory() { +#if defined(_WIN32) + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + if (GlobalMemoryStatusEx(&status)) { + return static_cast(status.ullAvailPhys); + } + return 0; +#elif defined(__APPLE__) + // On macOS, get free + inactive + purgeable memory + mach_port_t host = mach_host_self(); + vm_statistics64_data_t vm_stats; + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + + if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stats, &count) == KERN_SUCCESS) { + // Page size + vm_size_t page_size; + host_page_size(host, &page_size); + + // Available = free + inactive + purgeable (can be reclaimed) + uint64_t available = (uint64_t)(vm_stats.free_count + vm_stats.inactive_count + vm_stats.purgeable_count) * page_size; + return static_cast(available); + } + return 0; +#elif defined(__FreeBSD__) + // On FreeBSD, use vm.stats.vm.v_free_count and page size + unsigned int free_count = 0; + size_t len = sizeof(free_count); + if (sysctlbyname("vm.stats.vm.v_free_count", &free_count, &len, nullptr, 0) == 0) { + int page_size = getpagesize(); + // Also get inactive pages as they can be reclaimed + unsigned int inactive_count = 0; + len = sizeof(inactive_count); + sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_count, &len, nullptr, 0); + return static_cast((free_count + inactive_count)) * page_size; + } + return 0; +#elif defined(__linux__) + // On Linux, read MemAvailable from /proc/meminfo (most accurate) + FILE* f = fopen("/proc/meminfo", "r"); + if (f) { + char line[256]; + while (fgets(line, sizeof(line), f)) { + unsigned long long mem_kb; + if (sscanf(line, "MemAvailable: %llu kB", &mem_kb) == 1) { + fclose(f); + return static_cast(mem_kb * 1024); + } + } + fclose(f); + } + // Fallback to sysinfo + struct sysinfo info; + if (sysinfo(&info) == 0) { + return (info.freeram + info.bufferram) * info.mem_unit; + } + return 0; +#else + return 0; +#endif +} + +size_t get_resident_memory() { +#if defined(KTH_WITH_JEMALLOC) + // Force jemalloc to update its statistics by advancing the epoch + // This is necessary because jemalloc uses thread-local caching + uint64_t epoch = 1; + size_t epoch_sz = sizeof(epoch); + mallctl("epoch", &epoch, &epoch_sz, &epoch, epoch_sz); + + // Now read the stats + size_t allocated = 0; + size_t sz = sizeof(allocated); + if (mallctl("stats.allocated", &allocated, &sz, nullptr, 0) == 0) { + return allocated; + } + return 0; +#elif defined(_WIN32) + PROCESS_MEMORY_COUNTERS pmc; + if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { + return static_cast(pmc.WorkingSetSize); + } + return 0; +#elif defined(__APPLE__) + mach_task_basic_info info; + mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) { + return info.resident_size; + } + return 0; +#elif defined(__FreeBSD__) + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage) == 0) { + // ru_maxrss is in kilobytes on FreeBSD + return static_cast(usage.ru_maxrss) * 1024; + } + return 0; +#elif defined(__linux__) + // On Linux, read from /proc/self/statm + FILE* f = fopen("/proc/self/statm", "r"); + if (f) { + long pages = 0; + if (fscanf(f, "%*d %ld", &pages) == 1) { + fclose(f); + return pages * sysconf(_SC_PAGESIZE); + } + fclose(f); + } + return 0; +#else + return 0; +#endif +} + +bool is_jemalloc_active() { +#if defined(KTH_WITH_JEMALLOC) + // Try to get jemalloc version - if this succeeds, jemalloc is active + char const* version = nullptr; + size_t version_len = sizeof(version); + if (mallctl("version", &version, &version_len, nullptr, 0) == 0 && version != nullptr) { + return true; + } + return false; +#else + return false; +#endif +} + +std::string get_jemalloc_version() { +#if defined(KTH_WITH_JEMALLOC) + char const* version = nullptr; + size_t version_len = sizeof(version); + if (mallctl("version", &version, &version_len, nullptr, 0) == 0 && version != nullptr) { + return std::string(version); + } + return "unknown"; +#else + return "not compiled"; +#endif +} + +} // namespace kth diff --git a/src/infrastructure/src/utility/work.cpp b/src/infrastructure/src/utility/work.cpp deleted file mode 100644 index 43f70d41..00000000 --- a/src/infrastructure/src/utility/work.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include - -#include - -namespace kth { - -work::work(threadpool& pool, std::string const& name) - : name_(name) - , executor_(pool.executor()) - , strand_(::asio::make_strand(executor_)) - , sequence_(executor_) -{} - -} // namespace kth diff --git a/src/infrastructure/test/utility/threadpool.cpp b/src/infrastructure/test/utility/threadpool.cpp index 0c14e786..50b9c111 100644 --- a/src/infrastructure/test/utility/threadpool.cpp +++ b/src/infrastructure/test/utility/threadpool.cpp @@ -8,6 +8,7 @@ #include #include +#include #include using namespace kth; diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 14bb4b37..e7318911 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -90,68 +90,99 @@ if (ENABLE_SHARED) endif() +# Modern coroutine-based headers (KEEP) set(kth_headers - include/kth/network/acceptor.hpp include/kth/network/define.hpp include/kth/network/peer_session.hpp include/kth/network/peer_manager.hpp - include/kth/network/proxy.hpp - include/kth/network/channel.hpp - include/kth/network/hosts.hpp - include/kth/network/p2p.hpp include/kth/network/p2p_node.hpp - include/kth/network/sessions/session_outbound.hpp - include/kth/network/sessions/session_seed.hpp - include/kth/network/sessions/session_inbound.hpp - include/kth/network/sessions/session_manual.hpp - include/kth/network/sessions/session_batch.hpp - include/kth/network/sessions/session.hpp - include/kth/network/connector.hpp - include/kth/network/message_subscriber.hpp - include/kth/network/protocols/protocol_version_70002.hpp - include/kth/network/protocols/protocol_seed_31402.hpp - include/kth/network/protocols/protocol_timer.hpp - include/kth/network/protocols/protocol_version_31402.hpp - include/kth/network/protocols/protocol_address_31402.hpp - include/kth/network/protocols/protocol_ping_31402.hpp - include/kth/network/protocols/protocol_events.hpp - include/kth/network/protocols/protocol.hpp - include/kth/network/protocols/protocol_ping_60001.hpp - include/kth/network/protocols/protocol_reject_70002.hpp include/kth/network/protocols_coro.hpp include/kth/network/settings.hpp include/kth/network.hpp + include/kth/network/hosts.hpp # TODO: review - may need to modernize + + # Message handlers (one per message type) + include/kth/network/handlers/ping.hpp + include/kth/network/handlers/pong.hpp + + # ========================================================================= + # LEGACY FILES - MOVED TO deprecated/ FOLDER + # These files have been moved to src/network/deprecated/ and marked + # with DEPRECATED headers. They are kept for reference during migration. + # See doc/asio.md for migration details. + # ========================================================================= + # Legacy core headers - MOVED TO deprecated/ + # deprecated/acceptor.hpp + # deprecated/channel.hpp + # deprecated/connector.hpp + # deprecated/message_subscriber.hpp + # deprecated/p2p.hpp + # deprecated/proxy.hpp + # Legacy sessions - MOVED TO deprecated/sessions/ + # deprecated/sessions/session.hpp + # deprecated/sessions/session_batch.hpp + # deprecated/sessions/session_inbound.hpp + # deprecated/sessions/session_manual.hpp + # deprecated/sessions/session_outbound.hpp + # deprecated/sessions/session_seed.hpp + # Legacy protocols - MOVED TO deprecated/protocols/ + # deprecated/protocols/protocol.hpp + # deprecated/protocols/protocol_events.hpp + # deprecated/protocols/protocol_timer.hpp + # deprecated/protocols/protocol_address_31402.hpp + # deprecated/protocols/protocol_ping_31402.hpp + # deprecated/protocols/protocol_ping_60001.hpp + # deprecated/protocols/protocol_reject_70002.hpp + # deprecated/protocols/protocol_seed_31402.hpp + # deprecated/protocols/protocol_version_31402.hpp + # deprecated/protocols/protocol_version_70002.hpp ) +# Modern coroutine-based sources (KEEP) set(kth_sources - src/protocols/protocol.cpp - src/protocols/protocol_address_31402.cpp - src/protocols/protocol_events.cpp - src/protocols/protocol_ping_31402.cpp - src/protocols/protocol_ping_60001.cpp - src/protocols/protocol_reject_70002.cpp - src/protocols/protocol_seed_31402.cpp - src/protocols/protocol_timer.cpp - src/protocols/protocol_version_31402.cpp - src/protocols/protocol_version_70002.cpp - src/sessions/session.cpp - src/sessions/session_batch.cpp - src/sessions/session_inbound.cpp - src/sessions/session_manual.cpp - src/sessions/session_outbound.cpp - src/sessions/session_seed.cpp - src/acceptor.cpp - src/channel.cpp - src/connector.cpp - src/hosts.cpp - src/message_subscriber.cpp - src/p2p.cpp src/p2p_node.cpp src/peer_session.cpp src/peer_manager.cpp src/protocols_coro.cpp - src/proxy.cpp src/settings.cpp + src/version.cpp + src/hosts.cpp # TODO: review - may need to modernize + + # Message handlers (one per message type) + src/handlers/ping.cpp + src/handlers/pong.cpp + + # ========================================================================= + # LEGACY FILES - MOVED TO deprecated/ FOLDER + # These files have been moved to src/network/deprecated/ and marked + # with DEPRECATED headers. They are kept for reference during migration. + # See doc/asio.md for migration details. + # ========================================================================= + # Legacy core - MOVED TO deprecated/ + # deprecated/acceptor.cpp + # deprecated/channel.cpp + # deprecated/connector.cpp + # deprecated/message_subscriber.cpp + # deprecated/p2p.cpp + # deprecated/proxy.cpp + # Legacy sessions - MOVED TO deprecated/sessions/ + # deprecated/sessions/session.cpp + # deprecated/sessions/session_batch.cpp + # deprecated/sessions/session_inbound.cpp + # deprecated/sessions/session_manual.cpp + # deprecated/sessions/session_outbound.cpp + # deprecated/sessions/session_seed.cpp + # Legacy protocols - MOVED TO deprecated/protocols/ + # deprecated/protocols/protocol.cpp + # deprecated/protocols/protocol_events.cpp + # deprecated/protocols/protocol_timer.cpp + # deprecated/protocols/protocol_address_31402.cpp + # deprecated/protocols/protocol_ping_31402.cpp + # deprecated/protocols/protocol_ping_60001.cpp + # deprecated/protocols/protocol_reject_70002.cpp + # deprecated/protocols/protocol_seed_31402.cpp + # deprecated/protocols/protocol_version_31402.cpp + # deprecated/protocols/protocol_version_70002.cpp ) add_library(${PROJECT_NAME} ${MODE} ${kth_sources} ${kth_headers}) @@ -187,7 +218,8 @@ if (ENABLE_TEST AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") find_package(Catch2 3 REQUIRED) add_executable(kth_network_test - test/p2p.cpp + # TODO: Migrate tests from test/p2p.cpp to test/p2p_node.cpp before deleting + # test/p2p.cpp # Legacy test - COMMENTED OUT test/p2p_node.cpp test/peer_manager.cpp test/peer_session.cpp diff --git a/src/network/conanfile.py b/src/network/conanfile.py deleted file mode 100644 index 7becd77d..00000000 --- a/src/network/conanfile.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" -class KnuthNetworkConan(KnuthConanFileV2): - name = "network" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/network" - description = "Crypto P2P Network Library" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = { - "shared": [True, False], - "fPIC": [True, False], - "tests": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - - "verbose": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "tests": True, - "currency": "BCH", - - "march_strategy": "download_if_possible", - - "verbose": False, - "cmake_export_compile_commands": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "knuthbuildinfo.cmake", "include/*", "test/*" - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def requirements(self): - self.requires("domain/0.45.0", transitive_headers=True, transitive_libs=True) - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - def package_id(self): - KnuthConanFileV2.package_id(self) - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - - if not self.options.cmake_export_compile_commands: - cmake.build() - if self.options.tests: - cmake.test() - - def imports(self): - self.copy("*.h", "", "include") - - def package(self): - cmake = CMake(self) - cmake.install() - # rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - # rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) - # rmdir(self, os.path.join(self.package_folder, "res")) - # rmdir(self, os.path.join(self.package_folder, "share")) - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["network"] - - if self.settings.arch == "armv7": - self.cpp_info.system_libs.append("atomic") diff --git a/src/network/src/acceptor.cpp b/src/network/deprecated/acceptor.cpp similarity index 88% rename from src/network/src/acceptor.cpp rename to src/network/deprecated/acceptor.cpp index 5b0a376d..23fc237a 100644 --- a/src/network/src/acceptor.cpp +++ b/src/network/deprecated/acceptor.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/acceptor.hpp b/src/network/deprecated/acceptor.hpp similarity index 75% rename from src/network/include/kth/network/acceptor.hpp rename to src/network/deprecated/acceptor.hpp index 8802b67c..9238e631 100644 --- a/src/network/include/kth/network/acceptor.hpp +++ b/src/network/deprecated/acceptor.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_ACCEPTOR_HPP #define KTH_NETWORK_ACCEPTOR_HPP diff --git a/src/network/src/channel.cpp b/src/network/deprecated/channel.cpp similarity index 85% rename from src/network/src/channel.cpp rename to src/network/deprecated/channel.cpp index aba43e86..a334efcf 100644 --- a/src/network/src/channel.cpp +++ b/src/network/deprecated/channel.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -132,4 +142,4 @@ void channel::handle_inactivity(code const& ec) { stop(error::channel_timeout); } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/channel.hpp b/src/network/deprecated/channel.hpp similarity index 76% rename from src/network/include/kth/network/channel.hpp rename to src/network/deprecated/channel.hpp index b4acf022..8f47fa7c 100644 --- a/src/network/include/kth/network/channel.hpp +++ b/src/network/deprecated/channel.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_CHANNEL_HPP #define KTH_NETWORK_CHANNEL_HPP diff --git a/src/network/src/connector.cpp b/src/network/deprecated/connector.cpp similarity index 90% rename from src/network/src/connector.cpp rename to src/network/deprecated/connector.cpp index a2b2b742..5eaf5ae7 100644 --- a/src/network/src/connector.cpp +++ b/src/network/deprecated/connector.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/connector.hpp b/src/network/deprecated/connector.hpp similarity index 79% rename from src/network/include/kth/network/connector.hpp rename to src/network/deprecated/connector.hpp index b8bb8cf1..51f333ed 100644 --- a/src/network/include/kth/network/connector.hpp +++ b/src/network/deprecated/connector.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_CONNECTOR_HPP #define KTH_NETWORK_CONNECTOR_HPP diff --git a/src/network/src/message_subscriber.cpp b/src/network/deprecated/message_subscriber.cpp similarity index 93% rename from src/network/src/message_subscriber.cpp rename to src/network/deprecated/message_subscriber.cpp index 9fa6ce8f..31834984 100644 --- a/src/network/src/message_subscriber.cpp +++ b/src/network/deprecated/message_subscriber.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/message_subscriber.hpp b/src/network/deprecated/message_subscriber.hpp similarity index 93% rename from src/network/include/kth/network/message_subscriber.hpp rename to src/network/deprecated/message_subscriber.hpp index ad2fe4d5..a5262667 100644 --- a/src/network/include/kth/network/message_subscriber.hpp +++ b/src/network/deprecated/message_subscriber.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_MESSAGE_SUBSCRIBER_HPP #define KTH_NETWORK_MESSAGE_SUBSCRIBER_HPP diff --git a/src/network/src/p2p.cpp b/src/network/deprecated/p2p.cpp similarity index 92% rename from src/network/src/p2p.cpp rename to src/network/deprecated/p2p.cpp index beb3f0eb..79758127 100644 --- a/src/network/src/p2p.cpp +++ b/src/network/deprecated/p2p.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -113,7 +123,8 @@ void p2p::handle_manual_started(code const& ec, result_handler handler) { return; } - handle_hosts_loaded(hosts_.start(), handler); + // hosts_ loads from file in constructor, no explicit start needed + handle_hosts_loaded(error::success, handler); } void p2p::handle_hosts_loaded(code const& ec, result_handler handler) { @@ -236,8 +247,7 @@ session_outbound::ptr p2p::attach_outbound_session() { // taken around the entire section, which poses a deadlock risk. Instead this // is thread safe and idempotent, allowing it to be unguarded. bool p2p::stop() { - // This is the only stop operation that can fail. - auto const result = (hosts_.stop() == error::success); + // hosts_ saves to file in destructor, no explicit stop needed // Signal all current work to stop and free manual session. stopped_ = true; @@ -259,7 +269,7 @@ bool p2p::stop() { // Signal threadpool to stop accepting work now that subscribers are clear. threadpool_.stop(); - return result; + return true; } // This must be called from the thread that constructed this class (see join). @@ -359,24 +369,23 @@ size_t p2p::address_count() const { return hosts_.count(); } -code p2p::store(address const& address) { +bool p2p::store(address const& address) { return hosts_.store(address); } -void p2p::store(address::list const& addresses, result_handler handler) { - // Store is invoked on a new thread. - hosts_.store(addresses, handler); +size_t p2p::store(address::list const& addresses) { + return hosts_.store(addresses); } code p2p::fetch_address(address& out_address) const { return hosts_.fetch(out_address); } -code p2p::fetch_addresses(address::list& out_addresses) const { - return hosts_.fetch(out_addresses); +code p2p::fetch_addresses(address::list& out_addresses, size_t count) const { + return hosts_.fetch(out_addresses, count); } -code p2p::remove(address const& address) { +bool p2p::remove(address const& address) { return hosts_.remove(address); } diff --git a/src/network/include/kth/network/p2p.hpp b/src/network/deprecated/p2p.hpp similarity index 90% rename from src/network/include/kth/network/p2p.hpp rename to src/network/deprecated/p2p.hpp index ffc3d330..f151a1ba 100644 --- a/src/network/include/kth/network/p2p.hpp +++ b/src/network/deprecated/p2p.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_P2P_HPP #define KTH_NETWORK_P2P_HPP @@ -161,13 +171,13 @@ struct KN_API p2p : enable_shared_from_base, noncopyable { virtual size_t address_count() const; - /// Store an address. + /// Store an address (returns true if stored, false if duplicate/invalid). virtual - code store(address const& address); + bool store(address const& address); - /// Store a collection of addresses (asynchronous). + /// Store a collection of addresses (returns count stored). virtual - void store(address::list const& addresses, result_handler handler); + size_t store(address::list const& addresses); /// Get a randomly-selected address. virtual @@ -175,11 +185,11 @@ struct KN_API p2p : enable_shared_from_base, noncopyable { /// Get a list of stored hosts virtual - code fetch_addresses(address::list& out_addresses) const; + code fetch_addresses(address::list& out_addresses, size_t count) const; - /// Remove an address. + /// Remove an address (returns true if removed). virtual - code remove(address const& address); + bool remove(address const& address); // Pending connect collection. // ------------------------------------------------------------------------ diff --git a/src/network/src/protocols/protocol.cpp b/src/network/deprecated/protocols/protocol.cpp similarity index 74% rename from src/network/src/protocols/protocol.cpp rename to src/network/deprecated/protocols/protocol.cpp index 96aa4232..6f8131f1 100644 --- a/src/network/src/protocols/protocol.cpp +++ b/src/network/deprecated/protocols/protocol.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol.hpp b/src/network/deprecated/protocols/protocol.hpp similarity index 88% rename from src/network/include/kth/network/protocols/protocol.hpp rename to src/network/deprecated/protocols/protocol.hpp index 6a918a21..09503422 100644 --- a/src/network/include/kth/network/protocols/protocol.hpp +++ b/src/network/deprecated/protocols/protocol.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_HPP #define KTH_NETWORK_PROTOCOL_HPP diff --git a/src/network/src/protocols/protocol_address_31402.cpp b/src/network/deprecated/protocols/protocol_address_31402.cpp similarity index 86% rename from src/network/src/protocols/protocol_address_31402.cpp rename to src/network/deprecated/protocols/protocol_address_31402.cpp index a78a1664..3c68a2e2 100644 --- a/src/network/src/protocols/protocol_address_31402.cpp +++ b/src/network/deprecated/protocols/protocol_address_31402.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_address_31402.hpp b/src/network/deprecated/protocols/protocol_address_31402.hpp similarity index 72% rename from src/network/include/kth/network/protocols/protocol_address_31402.hpp rename to src/network/deprecated/protocols/protocol_address_31402.hpp index 5b69bb91..a1d7ad7c 100644 --- a/src/network/include/kth/network/protocols/protocol_address_31402.hpp +++ b/src/network/deprecated/protocols/protocol_address_31402.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_ADDRESS_31402_HPP #define KTH_NETWORK_PROTOCOL_ADDRESS_31402_HPP diff --git a/src/network/src/protocols/protocol_events.cpp b/src/network/deprecated/protocols/protocol_events.cpp similarity index 79% rename from src/network/src/protocols/protocol_events.cpp rename to src/network/deprecated/protocols/protocol_events.cpp index a6ecfaee..c237cdb4 100644 --- a/src/network/src/protocols/protocol_events.cpp +++ b/src/network/deprecated/protocols/protocol_events.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_events.hpp b/src/network/deprecated/protocols/protocol_events.hpp similarity index 77% rename from src/network/include/kth/network/protocols/protocol_events.hpp rename to src/network/deprecated/protocols/protocol_events.hpp index 19d89962..d40a06ff 100644 --- a/src/network/include/kth/network/protocols/protocol_events.hpp +++ b/src/network/deprecated/protocols/protocol_events.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_EVENTS_HPP #define KTH_NETWORK_PROTOCOL_EVENTS_HPP diff --git a/src/network/src/protocols/protocol_ping_31402.cpp b/src/network/deprecated/protocols/protocol_ping_31402.cpp similarity index 75% rename from src/network/src/protocols/protocol_ping_31402.cpp rename to src/network/deprecated/protocols/protocol_ping_31402.cpp index e4e9c5d7..939aa2c6 100644 --- a/src/network/src/protocols/protocol_ping_31402.cpp +++ b/src/network/deprecated/protocols/protocol_ping_31402.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_ping_31402.hpp b/src/network/deprecated/protocols/protocol_ping_31402.hpp similarity index 69% rename from src/network/include/kth/network/protocols/protocol_ping_31402.hpp rename to src/network/deprecated/protocols/protocol_ping_31402.hpp index abf2c1e5..e96338a9 100644 --- a/src/network/include/kth/network/protocols/protocol_ping_31402.hpp +++ b/src/network/deprecated/protocols/protocol_ping_31402.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_PING_31402_HPP #define KTH_NETWORK_PROTOCOL_PING_31402_HPP diff --git a/src/network/src/protocols/protocol_ping_60001.cpp b/src/network/deprecated/protocols/protocol_ping_60001.cpp similarity index 82% rename from src/network/src/protocols/protocol_ping_60001.cpp rename to src/network/deprecated/protocols/protocol_ping_60001.cpp index 18cd73ac..2325e671 100644 --- a/src/network/src/protocols/protocol_ping_60001.cpp +++ b/src/network/deprecated/protocols/protocol_ping_60001.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -100,4 +110,4 @@ bool protocol_ping_60001::handle_receive_pong(code const& ec, pong_const_ptr mes return false; } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/protocols/protocol_ping_60001.hpp b/src/network/deprecated/protocols/protocol_ping_60001.hpp similarity index 72% rename from src/network/include/kth/network/protocols/protocol_ping_60001.hpp rename to src/network/deprecated/protocols/protocol_ping_60001.hpp index 5894e6ad..a7c5819f 100644 --- a/src/network/include/kth/network/protocols/protocol_ping_60001.hpp +++ b/src/network/deprecated/protocols/protocol_ping_60001.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_PING_60001_HPP #define KTH_NETWORK_PROTOCOL_PING_60001_HPP diff --git a/src/network/src/protocols/protocol_reject_70002.cpp b/src/network/deprecated/protocols/protocol_reject_70002.cpp similarity index 78% rename from src/network/src/protocols/protocol_reject_70002.cpp rename to src/network/deprecated/protocols/protocol_reject_70002.cpp index fab86b57..19ce4a8a 100644 --- a/src/network/src/protocols/protocol_reject_70002.cpp +++ b/src/network/deprecated/protocols/protocol_reject_70002.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_reject_70002.hpp b/src/network/deprecated/protocols/protocol_reject_70002.hpp similarity index 66% rename from src/network/include/kth/network/protocols/protocol_reject_70002.hpp rename to src/network/deprecated/protocols/protocol_reject_70002.hpp index 23387b6d..72b969df 100644 --- a/src/network/include/kth/network/protocols/protocol_reject_70002.hpp +++ b/src/network/deprecated/protocols/protocol_reject_70002.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_REJECT_70002_HPP #define KTH_NETWORK_PROTOCOL_REJECT_70002_HPP @@ -40,4 +50,3 @@ class KN_API protocol_reject_70002 } // namespace kth::network #endif - diff --git a/src/network/src/protocols/protocol_seed_31402.cpp b/src/network/deprecated/protocols/protocol_seed_31402.cpp similarity index 85% rename from src/network/src/protocols/protocol_seed_31402.cpp rename to src/network/deprecated/protocols/protocol_seed_31402.cpp index 00887717..cfec7d48 100644 --- a/src/network/src/protocols/protocol_seed_31402.cpp +++ b/src/network/deprecated/protocols/protocol_seed_31402.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -118,4 +128,4 @@ void protocol_seed_31402::handle_store_addresses(code const& ec) { set_event(error::channel_stopped); } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/protocols/protocol_seed_31402.hpp b/src/network/deprecated/protocols/protocol_seed_31402.hpp similarity index 75% rename from src/network/include/kth/network/protocols/protocol_seed_31402.hpp rename to src/network/deprecated/protocols/protocol_seed_31402.hpp index beae0902..b4f9debd 100644 --- a/src/network/include/kth/network/protocols/protocol_seed_31402.hpp +++ b/src/network/deprecated/protocols/protocol_seed_31402.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_SEED_31402_HPP #define KTH_NETWORK_PROTOCOL_SEED_31402_HPP diff --git a/src/network/src/protocols/protocol_timer.cpp b/src/network/deprecated/protocols/protocol_timer.cpp similarity index 77% rename from src/network/src/protocols/protocol_timer.cpp rename to src/network/deprecated/protocols/protocol_timer.cpp index 839d839a..e47fc86d 100644 --- a/src/network/src/protocols/protocol_timer.cpp +++ b/src/network/deprecated/protocols/protocol_timer.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_timer.hpp b/src/network/deprecated/protocols/protocol_timer.hpp similarity index 75% rename from src/network/include/kth/network/protocols/protocol_timer.hpp rename to src/network/deprecated/protocols/protocol_timer.hpp index e4a89ae5..84fec249 100644 --- a/src/network/include/kth/network/protocols/protocol_timer.hpp +++ b/src/network/deprecated/protocols/protocol_timer.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_TIMER_HPP #define KTH_NETWORK_PROTOCOL_TIMER_HPP diff --git a/src/network/src/protocols/protocol_version_31402.cpp b/src/network/deprecated/protocols/protocol_version_31402.cpp similarity index 93% rename from src/network/src/protocols/protocol_version_31402.cpp rename to src/network/deprecated/protocols/protocol_version_31402.cpp index 3166f585..bbb93b87 100644 --- a/src/network/src/protocols/protocol_version_31402.cpp +++ b/src/network/deprecated/protocols/protocol_version_31402.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_version_31402.hpp b/src/network/deprecated/protocols/protocol_version_31402.hpp similarity index 81% rename from src/network/include/kth/network/protocols/protocol_version_31402.hpp rename to src/network/deprecated/protocols/protocol_version_31402.hpp index 430410c6..347df6cf 100644 --- a/src/network/include/kth/network/protocols/protocol_version_31402.hpp +++ b/src/network/deprecated/protocols/protocol_version_31402.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_VERSION_31402_HPP #define KTH_NETWORK_PROTOCOL_VERSION_31402_HPP @@ -70,4 +80,3 @@ class KN_API protocol_version_31402 } // namespace kth::network #endif - diff --git a/src/network/src/protocols/protocol_version_70002.cpp b/src/network/deprecated/protocols/protocol_version_70002.cpp similarity index 88% rename from src/network/src/protocols/protocol_version_70002.cpp rename to src/network/deprecated/protocols/protocol_version_70002.cpp index f073c02a..402a79f7 100644 --- a/src/network/src/protocols/protocol_version_70002.cpp +++ b/src/network/deprecated/protocols/protocol_version_70002.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/protocols/protocol_version_70002.hpp b/src/network/deprecated/protocols/protocol_version_70002.hpp similarity index 80% rename from src/network/include/kth/network/protocols/protocol_version_70002.hpp rename to src/network/deprecated/protocols/protocol_version_70002.hpp index 04f063d7..89ce345f 100644 --- a/src/network/include/kth/network/protocols/protocol_version_70002.hpp +++ b/src/network/deprecated/protocols/protocol_version_70002.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROTOCOL_VERSION_70002_HPP #define KTH_NETWORK_PROTOCOL_VERSION_70002_HPP diff --git a/src/network/src/proxy.cpp b/src/network/deprecated/proxy.cpp similarity index 93% rename from src/network/src/proxy.cpp rename to src/network/deprecated/proxy.cpp index c6b7c866..85591219 100644 --- a/src/network/src/proxy.cpp +++ b/src/network/deprecated/proxy.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #define BOOST_BIND_NO_PLACEHOLDERS @@ -278,4 +288,4 @@ bool proxy::stopped() const { return stopped_; } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/proxy.hpp b/src/network/deprecated/proxy.hpp similarity index 87% rename from src/network/include/kth/network/proxy.hpp rename to src/network/deprecated/proxy.hpp index b6175076..e1cf8178 100644 --- a/src/network/include/kth/network/proxy.hpp +++ b/src/network/deprecated/proxy.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_PROXY_HPP #define KTH_NETWORK_PROXY_HPP @@ -125,4 +135,3 @@ class KN_API proxy } // namespace kth::network #endif - diff --git a/src/network/src/sessions/session.cpp b/src/network/deprecated/sessions/session.cpp similarity index 92% rename from src/network/src/sessions/session.cpp rename to src/network/deprecated/sessions/session.cpp index 8e3f8a6f..b799b6af 100644 --- a/src/network/src/sessions/session.cpp +++ b/src/network/deprecated/sessions/session.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include diff --git a/src/network/include/kth/network/sessions/session.hpp b/src/network/deprecated/sessions/session.hpp similarity index 92% rename from src/network/include/kth/network/sessions/session.hpp rename to src/network/deprecated/sessions/session.hpp index 202e1b98..5aa11600 100644 --- a/src/network/include/kth/network/sessions/session.hpp +++ b/src/network/deprecated/sessions/session.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_SESSION_HPP #define KTH_NETWORK_SESSION_HPP diff --git a/src/network/src/sessions/session_batch.cpp b/src/network/deprecated/sessions/session_batch.cpp similarity index 82% rename from src/network/src/sessions/session_batch.cpp rename to src/network/deprecated/sessions/session_batch.cpp index 5df30d23..a58342fb 100644 --- a/src/network/src/sessions/session_batch.cpp +++ b/src/network/deprecated/sessions/session_batch.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -92,4 +102,4 @@ void session_batch::handle_connect(code const& ec, channel::ptr channel, connect handler(error::success, channel); } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/sessions/session_batch.hpp b/src/network/deprecated/sessions/session_batch.hpp similarity index 68% rename from src/network/include/kth/network/sessions/session_batch.hpp rename to src/network/deprecated/sessions/session_batch.hpp index 93e7cbdf..843b6598 100644 --- a/src/network/include/kth/network/sessions/session_batch.hpp +++ b/src/network/deprecated/sessions/session_batch.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_SESSION_BATCH_HPP #define KTH_NETWORK_SESSION_BATCH_HPP diff --git a/src/network/src/sessions/session_inbound.cpp b/src/network/deprecated/sessions/session_inbound.cpp similarity index 90% rename from src/network/src/sessions/session_inbound.cpp rename to src/network/deprecated/sessions/session_inbound.cpp index 86dca599..2f633f75 100644 --- a/src/network/src/sessions/session_inbound.cpp +++ b/src/network/deprecated/sessions/session_inbound.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -160,4 +170,4 @@ void session_inbound::handshake_complete(channel::ptr channel, result_handler ha session::handshake_complete(channel, handle_started); } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/sessions/session_inbound.hpp b/src/network/deprecated/sessions/session_inbound.hpp similarity index 75% rename from src/network/include/kth/network/sessions/session_inbound.hpp rename to src/network/deprecated/sessions/session_inbound.hpp index f30dbd42..3dae66d0 100644 --- a/src/network/include/kth/network/sessions/session_inbound.hpp +++ b/src/network/deprecated/sessions/session_inbound.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_SESSION_INBOUND_HPP #define KTH_NETWORK_SESSION_INBOUND_HPP diff --git a/src/network/src/sessions/session_manual.cpp b/src/network/deprecated/sessions/session_manual.cpp similarity index 90% rename from src/network/src/sessions/session_manual.cpp rename to src/network/deprecated/sessions/session_manual.cpp index a176558d..f2088cff 100644 --- a/src/network/src/sessions/session_manual.cpp +++ b/src/network/deprecated/sessions/session_manual.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -142,4 +152,4 @@ void session_manual::handle_channel_stop(code const& ec, std::string const& host } } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/sessions/session_manual.hpp b/src/network/deprecated/sessions/session_manual.hpp similarity index 78% rename from src/network/include/kth/network/sessions/session_manual.hpp rename to src/network/deprecated/sessions/session_manual.hpp index 48caeebb..8ff6fbff 100644 --- a/src/network/include/kth/network/sessions/session_manual.hpp +++ b/src/network/deprecated/sessions/session_manual.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_SESSION_MANUAL_HPP #define KTH_NETWORK_SESSION_MANUAL_HPP diff --git a/src/network/src/sessions/session_outbound.cpp b/src/network/deprecated/sessions/session_outbound.cpp similarity index 90% rename from src/network/src/sessions/session_outbound.cpp rename to src/network/deprecated/sessions/session_outbound.cpp index 6cf72cb9..f59892d9 100644 --- a/src/network/src/sessions/session_outbound.cpp +++ b/src/network/deprecated/sessions/session_outbound.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -158,4 +168,4 @@ void session_outbound::do_unpend(code const& ec, channel::ptr channel, result_ha handle_started(ec); } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/sessions/session_outbound.hpp b/src/network/deprecated/sessions/session_outbound.hpp similarity index 76% rename from src/network/include/kth/network/sessions/session_outbound.hpp rename to src/network/deprecated/sessions/session_outbound.hpp index eeee2c0c..403fef6f 100644 --- a/src/network/include/kth/network/sessions/session_outbound.hpp +++ b/src/network/deprecated/sessions/session_outbound.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_SESSION_OUTBOUND_HPP #define KTH_NETWORK_SESSION_OUTBOUND_HPP diff --git a/src/network/src/sessions/session_seed.cpp b/src/network/deprecated/sessions/session_seed.cpp similarity index 91% rename from src/network/src/sessions/session_seed.cpp rename to src/network/deprecated/sessions/session_seed.cpp index 8cc89efe..5d7c8ee4 100644 --- a/src/network/src/sessions/session_seed.cpp +++ b/src/network/deprecated/sessions/session_seed.cpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #include #include @@ -178,4 +188,4 @@ void session_seed::handle_complete(size_t start_size, result_handler handler) { handler(increase ? error::success : error::peer_throttling); } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/include/kth/network/sessions/session_seed.hpp b/src/network/deprecated/sessions/session_seed.hpp similarity index 76% rename from src/network/include/kth/network/sessions/session_seed.hpp rename to src/network/deprecated/sessions/session_seed.hpp index c6fb84d8..48a51020 100644 --- a/src/network/include/kth/network/sessions/session_seed.hpp +++ b/src/network/deprecated/sessions/session_seed.hpp @@ -2,6 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// ============================================================================ +// DEPRECATED - This file is scheduled for removal +// ============================================================================ +// This file is part of the legacy P2P implementation that is being replaced +// by modern C++23 coroutines and Asio. See doc/asio.md for migration details. +// +// DO NOT USE THIS FILE IN NEW CODE. +// Replacement: Use p2p_node.hpp, peer_session.hpp, protocols_coro.hpp +// ============================================================================ + #ifndef KTH_NETWORK_SESSION_SEED_HPP #define KTH_NETWORK_SESSION_SEED_HPP @@ -50,4 +60,3 @@ struct KN_API session_seed : session, track { } // namespace kth::network #endif - diff --git a/src/network/include/kth/network.hpp b/src/network/include/kth/network.hpp index aa80b8ea..5ac5663e 100644 --- a/src/network/include/kth/network.hpp +++ b/src/network/include/kth/network.hpp @@ -13,34 +13,43 @@ */ #include -#include -#include -#include #include -#include -#include -#include +#include + +#include + +// Modern coroutine-based networking (keep these) #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include + +// Legacy networking - COMMENTED OUT (coroutine migration cleanup) +// These are replaced by p2p_node + peer_session + peer_manager + protocols_coro +// #include +// #include +// #include +#include // TODO: review - may need to keep or modernize +// #include +// #include +// #include +// Legacy protocols - COMMENTED OUT, replaced by protocols_coro.hpp +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// Legacy sessions - COMMENTED OUT, replaced by p2p_node + peer_session +// #include +// #include +// #include +// #include +// #include +// #include #endif diff --git a/src/network/include/kth/network/handlers/ping.hpp b/src/network/include/kth/network/handlers/ping.hpp new file mode 100644 index 00000000..6fb26c68 --- /dev/null +++ b/src/network/include/kth/network/handlers/ping.hpp @@ -0,0 +1,31 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NETWORK_HANDLERS_PING_HPP +#define KTH_NETWORK_HANDLERS_PING_HPP + +#include +#include +#include + +#include + +namespace kth::network { + +enum class message_result; + +namespace handlers::ping { + +/// Handle incoming ping message - respond with pong +/// Receives the already-parsed ping message +[[nodiscard]] +KN_API ::asio::awaitable handle( + peer_session& peer, + domain::message::ping const& msg); + +} // namespace handlers::ping + +} // namespace kth::network + +#endif // KTH_NETWORK_HANDLERS_PING_HPP diff --git a/src/network/include/kth/network/handlers/pong.hpp b/src/network/include/kth/network/handlers/pong.hpp new file mode 100644 index 00000000..55e787da --- /dev/null +++ b/src/network/include/kth/network/handlers/pong.hpp @@ -0,0 +1,31 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NETWORK_HANDLERS_PONG_HPP +#define KTH_NETWORK_HANDLERS_PONG_HPP + +#include +#include +#include + +#include + +namespace kth::network { + +enum class message_result; + +namespace handlers::pong { + +/// Handle incoming pong message - just acknowledge +/// Receives the already-parsed pong message +[[nodiscard]] +KN_API ::asio::awaitable handle( + peer_session& peer, + domain::message::pong const& msg); + +} // namespace handlers::pong + +} // namespace kth::network + +#endif // KTH_NETWORK_HANDLERS_PONG_HPP diff --git a/src/network/include/kth/network/hosts.hpp b/src/network/include/kth/network/hosts.hpp index 7401cc7b..ed494437 100644 --- a/src/network/include/kth/network/hosts.hpp +++ b/src/network/include/kth/network/hosts.hpp @@ -5,63 +5,93 @@ #ifndef KTH_NETWORK_HOSTS_HPP #define KTH_NETWORK_HOSTS_HPP -#include #include #include #include #include + +#include + #include #include #include namespace kth::network { -/// This class is thread safe. -/// The hosts class manages a thread-safe dynamic store of network addresses. -/// The store can be loaded and saved from/to the specified file path. -/// The file is a line-oriented set of infrastructure::config::authority serializations. -/// Duplicate addresses and those with zero-valued ports are disacarded. +// Hash function for network_address (uses ip + port) +struct address_hash { + using address = domain::message::network_address; + + size_t operator()(address const& addr) const noexcept { + // Combine ip and port into a hash + size_t seed = 0; + auto const& ip = addr.ip(); + for (auto byte : ip) { + seed ^= std::hash{}(byte) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + seed ^= std::hash{}(addr.port()) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +// Equality for network_address (compares ip + port only) +struct address_equal { + using address = domain::message::network_address; + + bool operator()(address const& a, address const& b) const noexcept { + return a.ip() == b.ip() && a.port() == b.port(); + } +}; + +/// Thread-safe host address store using lock-free concurrent set. +/// Manages network addresses for peer discovery. +/// File persistence is handled automatically (load in ctor, save in dtor). class KN_API hosts : noncopyable { public: using ptr = std::shared_ptr; using address = domain::message::network_address; - using result_handler = handle0; - /// Construct an instance. - hosts(settings const& settings); + /// Construct an instance (loads from file if exists). + explicit hosts(settings const& settings); - /// Load hosts file if found. - virtual code start(); + /// Destructor (saves to file). + ~hosts(); - // Save hosts to file. - virtual code stop(); + /// Get current address count. + [[nodiscard]] + size_t count() const; - virtual size_t count() const; - virtual code fetch(address& out) const; - virtual code fetch(address::list& out) const; - virtual code remove(address const& host); - virtual code store(address const& host); - virtual void store(address::list const& hosts, result_handler handler); + /// Fetch a random address. + [[nodiscard]] + code fetch(address& out) const; -private: - using list = boost::circular_buffer
; - using iterator = list::iterator; + /// Fetch multiple random addresses. + [[nodiscard]] + code fetch(address::list& out, size_t count) const; - iterator find(address const& host); + /// Remove an address. + bool remove(address const& host); - size_t const capacity_; + /// Store an address (filters non-routable). + bool store(address const& host); - // These are protected by a mutex. - list buffer_; - std::atomic stopped_; - mutable upgrade_mutex mutex_; + /// Store multiple addresses (filters non-routable). + size_t store(address::list const& hosts); + +private: + using address_set = boost::concurrent_flat_set; - // HACK: we use this because the buffer capacity cannot be set to zero. + void load_from_file(); + void save_to_file() const; + + size_t const capacity_; bool const disabled_; kth::path const file_path_; + + // Lock-free concurrent set for addresses + address_set addresses_; }; } // namespace kth::network #endif - diff --git a/src/network/include/kth/network/p2p_node.hpp b/src/network/include/kth/network/p2p_node.hpp index db17ed20..cd41dd22 100644 --- a/src/network/include/kth/network/p2p_node.hpp +++ b/src/network/include/kth/network/p2p_node.hpp @@ -7,10 +7,13 @@ #include #include +#include #include #include #include +#include + #include #include @@ -31,6 +34,96 @@ namespace kth::network { +using kth::awaitable_expected; + +// ============================================================================= +// Message Handler Interface +// ============================================================================= + +/// Result of processing a message +enum class message_result { + continue_processing, // Keep processing messages + disconnect, // Disconnect the peer + handled, // Message was handled, continue + not_handled // Message was not handled by this handler +}; + +/// Handler for incoming raw messages +/// Return message_result to indicate what to do next +using message_handler_fn = std::function<::asio::awaitable( + peer_session& peer, + raw_message const& msg +)>; + +/// Handler for typed (already parsed) messages +/// Template parameter Message is the domain message type (e.g., domain::message::ping) +template +using typed_message_handler_fn = std::function<::asio::awaitable( + peer_session& peer, + Message const& msg +)>; + +/// Creates a raw message handler from a typed handler +/// Handles parsing boilerplate: byte_reader creation, from_data call, error handling +template +message_handler_fn make_handler(typed_message_handler_fn typed_handler) { + return [typed_handler = std::move(typed_handler)]( + peer_session& peer, + raw_message const& raw + ) -> ::asio::awaitable { + byte_reader reader(raw.payload); + auto result = Message::from_data(reader, peer.negotiated_version()); + + if (!result) { + spdlog::debug("[handler] Failed to parse {} from [{}]", + Message::command, peer.authority()); + co_return message_result::continue_processing; + } + + co_return co_await typed_handler(peer, *result); + }; +} + +/// Overload for function pointers +template +message_handler_fn make_handler( + ::asio::awaitable(*handler)(peer_session&, Message const&) +) { + return make_handler(typed_message_handler_fn(handler)); +} + +/// Dispatcher that routes messages to appropriate handlers +/// This is the mutable part - handlers can be added/removed +class KN_API message_dispatcher { +public: + /// Process a message through registered handlers + /// Returns true to continue, false to disconnect + ::asio::awaitable dispatch(peer_session& peer, raw_message const& msg); + + /// Register a raw handler for a specific command + void register_handler(std::string const& command, message_handler_fn handler); + + /// Register a typed handler for a specific message type + /// The message type must have a static 'command' string member + template + void register_handler(typed_message_handler_fn handler) { + handlers_[Message::command] = make_handler(std::move(handler)); + } + + /// Register a typed handler from a function pointer + template + void register_handler(::asio::awaitable(*handler)(peer_session&, Message const&)) { + handlers_[Message::command] = make_handler(handler); + } + + /// Register a default handler for unhandled messages + void set_default_handler(message_handler_fn handler); + +private: + boost::unordered_flat_map handlers_; + message_handler_fn default_handler_; +}; + // ============================================================================= // Connection result (combines peer_session with handshake info) // ============================================================================= @@ -89,7 +182,7 @@ class KN_API p2p_node { // ------------------------------------------------------------------------- /// Connect to a specific peer and perform handshake - ::asio::awaitable> connect( + awaitable_expected connect( std::string const& host, uint16_t port); @@ -99,9 +192,9 @@ class KN_API p2p_node { [[nodiscard]] size_t address_count() const; - code store(address const& addr); + bool store(address const& addr); code fetch_address(address& out) const; - code remove(address const& addr); + bool remove(address const& addr); // Broadcasting // ------------------------------------------------------------------------- @@ -123,6 +216,17 @@ class KN_API p2p_node { [[nodiscard]] std::vector get_peers() const; + /// Get the thread pool + [[nodiscard]] + threadpool& thread_pool(); + + // Message handling + // ------------------------------------------------------------------------- + + /// Get the message dispatcher for registering handlers + [[nodiscard]] + message_dispatcher& dispatcher(); + private: // Internal coroutines ::asio::awaitable run_seeding(); @@ -131,10 +235,16 @@ class KN_API p2p_node { ::asio::awaitable run_peer_protocols(peer_session::ptr peer); ::asio::awaitable maintain_outbound_connections(); + // Helper for seeding - takes params by value to avoid lambda capture issues + ::asio::awaitable connect_to_seed( + std::string seed_host, + uint16_t seed_port, + std::shared_ptr> seeds_completed); + uint64_t generate_nonce(); settings const& settings_; - ::asio::thread_pool pool_; + threadpool pool_; peer_manager manager_; hosts hosts_; @@ -144,6 +254,9 @@ class KN_API p2p_node { std::atomic stopped_{true}; std::atomic seeded_{false}; kth::atomic top_block_; + + // Message dispatcher for routing messages to handlers + message_dispatcher dispatcher_; }; } // namespace kth::network diff --git a/src/network/include/kth/network/peer_session.hpp b/src/network/include/kth/network/peer_session.hpp index 6868a135..74f54e07 100644 --- a/src/network/include/kth/network/peer_session.hpp +++ b/src/network/include/kth/network/peer_session.hpp @@ -28,6 +28,8 @@ namespace kth::network { +using kth::awaitable_expected; + // ============================================================================= // peer_session: Modern coroutine-based peer connection handler // ============================================================================= @@ -120,6 +122,28 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] inbound_channel& messages(); + // ------------------------------------------------------------------------- + // Response channels (for request/response patterns like getheaders/headers) + // ------------------------------------------------------------------------- + + /// Channel for headers responses (filled by message handler when headers arrives) + using response_channel = concurrent_channel; + + /// Get the channel for headers responses + /// The dispatcher should route 'headers' messages here when someone is waiting + [[nodiscard]] + response_channel& headers_responses(); + + /// Get the channel for block responses + /// The dispatcher should route 'block' messages here when someone is waiting + [[nodiscard]] + response_channel& block_responses(); + + /// Get the channel for address responses + /// The dispatcher should route 'addr' messages here when someone is waiting + [[nodiscard]] + response_channel& addr_responses(); + // ------------------------------------------------------------------------- // Properties // ------------------------------------------------------------------------- @@ -166,7 +190,7 @@ class KN_API peer_session : public std::enable_shared_from_this { ::asio::awaitable expiration_timer(); /// Read a complete message (heading + payload) - ::asio::awaitable> read_message(); + awaitable_expected read_message(); /// Signal activity (resets inactivity timer) void signal_activity(); @@ -183,6 +207,12 @@ class KN_API peer_session : public std::enable_shared_from_this { outbound_channel outbound_; inbound_channel inbound_; + // Response channels for request/response patterns + // These are filled by the dispatcher when specific responses arrive + response_channel headers_responses_; + response_channel block_responses_; + response_channel addr_responses_; + // Timers ::asio::steady_timer inactivity_timer_; ::asio::steady_timer expiration_timer_; @@ -222,7 +252,7 @@ class KN_API peer_session : public std::enable_shared_from_this { /// @param timeout Connection timeout /// @return awaitable that yields a peer_session::ptr or error code [[nodiscard]] -::asio::awaitable> async_connect( +awaitable_expected async_connect( ::asio::any_io_executor executor, std::string const& hostname, uint16_t port, @@ -231,7 +261,7 @@ ::asio::awaitable> async_connect( /// Connect to a peer by authority (address:port) [[nodiscard]] -::asio::awaitable> async_connect( +awaitable_expected async_connect( ::asio::any_io_executor executor, infrastructure::config::authority const& authority, settings const& settings, @@ -242,7 +272,7 @@ ::asio::awaitable> async_connect( /// @param settings Network settings for the connection /// @return awaitable that yields a peer_session::ptr or error code [[nodiscard]] -::asio::awaitable> async_accept( +awaitable_expected async_accept( ::asio::ip::tcp::acceptor& acceptor, settings const& settings); @@ -251,7 +281,7 @@ ::asio::awaitable> async_accept( /// @param port The port to listen on /// @return awaitable that yields an acceptor or error code [[nodiscard]] -::asio::awaitable> async_listen( +awaitable_expected<::asio::ip::tcp::acceptor> async_listen( ::asio::any_io_executor executor, uint16_t port); diff --git a/src/network/include/kth/network/protocols_coro.hpp b/src/network/include/kth/network/protocols_coro.hpp index d50bf503..98d80eb2 100644 --- a/src/network/include/kth/network/protocols_coro.hpp +++ b/src/network/include/kth/network/protocols_coro.hpp @@ -5,6 +5,56 @@ #ifndef KTH_NETWORK_PROTOCOLS_CORO_HPP #define KTH_NETWORK_PROTOCOLS_CORO_HPP +// ============================================================================= +// Network Layer Protocol Handlers (Coroutine-based) +// ============================================================================= +// +// This file contains coroutine-based implementations of Bitcoin P2P network +// layer protocols. These are generic networking protocols that don't require +// blockchain state. +// +// WHAT THIS FILE PROVIDES: +// ------------------------ +// - perform_handshake() : Version/verack exchange and protocol negotiation +// - run_ping_pong() : Keepalive ping/pong loop +// - request_addresses() : Request peer addresses (getaddr) +// - send_addresses() : Send peer addresses (addr) +// +// LEGACY FILES THIS REPLACES: +// --------------------------- +// Once fully integrated, these coroutine functions replace the following +// callback-based protocol classes: +// +// | Coroutine Function | Replaces Legacy Files | +// |-----------------------|----------------------------------------------------| +// | perform_handshake() | protocols/protocol_version_31402.hpp/.cpp | +// | | protocols/protocol_version_70002.hpp/.cpp | +// | run_ping_pong() | protocols/protocol_ping_31402.hpp/.cpp | +// | | protocols/protocol_ping_60001.hpp/.cpp | +// | request_addresses() | protocols/protocol_address_31402.hpp/.cpp | +// | send_addresses() | protocols/protocol_seed_31402.hpp/.cpp | +// +// BASE CLASSES (also to be removed): +// | protocols/protocol.hpp/.cpp | +// | protocols/protocol_events.hpp/.cpp | +// | protocols/protocol_timer.hpp/.cpp | +// +// NOT REPLACED HERE (handled elsewhere or deprecated): +// | protocols/protocol_reject_70002.hpp/.cpp - Reject messages (BIP 61) | +// +// USAGE: +// ------ +// These functions are designed to be used with peer_session and are typically +// called from p2p_node or higher-level code: +// +// auto result = co_await perform_handshake(peer, config); +// if (!result) { /* handle error */ } +// +// // Run ping/pong in background +// asio::co_spawn(executor, run_ping_pong(peer, 120s), asio::detached); +// +// ============================================================================= + #include #include #include @@ -22,6 +72,8 @@ namespace kth::network { +using kth::awaitable_expected; + // ============================================================================= // Message Helpers // ============================================================================= @@ -31,7 +83,7 @@ namespace kth::network { /// @param peer The peer session to receive from /// @param timeout Maximum time to wait for the message template -::asio::awaitable> wait_for_message( +awaitable_expected wait_for_message( peer_session& peer, std::chrono::seconds timeout) { @@ -77,7 +129,7 @@ ::asio::awaitable> wait_for_message( /// Wait for any message from the peer (returns raw_message) /// @param peer The peer session to receive from /// @param timeout Maximum time to wait -::asio::awaitable> wait_for_any_message( +awaitable_expected wait_for_any_message( peer_session& peer, std::chrono::seconds timeout); @@ -111,7 +163,7 @@ struct handshake_result { /// @param config Handshake configuration /// @return handshake_result on success, error code on failure [[nodiscard]] -KN_API ::asio::awaitable> perform_handshake( +KN_API awaitable_expected perform_handshake( peer_session& peer, handshake_config const& config); @@ -146,7 +198,7 @@ KN_API ::asio::awaitable run_ping_pong( /// @param timeout Maximum time to wait for response /// @return Vector of addresses or error [[nodiscard]] -KN_API ::asio::awaitable> request_addresses( +KN_API awaitable_expected request_addresses( peer_session& peer, std::chrono::seconds timeout); @@ -158,6 +210,201 @@ KN_API ::asio::awaitable send_addresses( peer_session& peer, domain::message::address const& addresses); +// ============================================================================= +// Blockchain Protocol Handlers (Headers-First Sync) +// ============================================================================= +// +// These protocols handle blockchain synchronization. Unlike the network layer +// protocols above, these require interaction with blockchain state. +// +// SYNC FLOW (Headers-First): +// -------------------------- +// 1. request_headers() - Send getheaders, receive headers +// 2. Validate and store headers in blockchain +// 3. request_blocks() - Send getdata for blocks we need +// 4. Receive and validate blocks +// 5. Repeat until synced +// +// ANNOUNCEMENT HANDLING: +// ---------------------- +// - handle_inv() - Process inventory announcements from peers +// - handle_headers() - Process unsolicited headers (after sendheaders) +// +// ============================================================================= + +// ----------------------------------------------------------------------------- +// Header Sync Protocol +// ----------------------------------------------------------------------------- + +/// Request headers from a peer using getheaders message +/// @param peer The peer session +/// @param locator_hashes Block locator hashes (most recent first) +/// @param stop_hash Hash to stop at (null_hash for no limit) +/// @param timeout Maximum time to wait for response +/// @return Headers message or error +[[nodiscard]] +KN_API awaitable_expected request_headers( + peer_session& peer, + hash_list const& locator_hashes, + hash_digest const& stop_hash, + std::chrono::seconds timeout); + +/// Request headers starting from a single known hash +/// Convenience wrapper that creates a single-element locator +[[nodiscard]] +KN_API awaitable_expected request_headers_from( + peer_session& peer, + hash_digest const& from_hash, + std::chrono::seconds timeout); + +// ----------------------------------------------------------------------------- +// Block Sync Protocol +// ----------------------------------------------------------------------------- + +/// Request blocks using getdata message +/// @param peer The peer session +/// @param block_hashes Hashes of blocks to request +/// @return Error code (blocks arrive via message handler) +[[nodiscard]] +KN_API ::asio::awaitable request_blocks( + peer_session& peer, + hash_list const& block_hashes); + +/// Request a single block +/// @param peer The peer session +/// @param block_hash Hash of block to request +/// @param timeout Maximum time to wait for block +/// @return Block message or error +[[nodiscard]] +KN_API awaitable_expected request_block( + peer_session& peer, + hash_digest const& block_hash, + std::chrono::seconds timeout); + +// ----------------------------------------------------------------------------- +// Inventory Protocol +// ----------------------------------------------------------------------------- + +/// Send inventory announcement to peer +/// @param peer The peer session +/// @param inv Inventory to announce +[[nodiscard]] +KN_API ::asio::awaitable send_inventory( + peer_session& peer, + domain::message::inventory const& inv); + +/// Request data for inventory items +/// @param peer The peer session +/// @param inv Inventory items to request +[[nodiscard]] +KN_API ::asio::awaitable send_getdata( + peer_session& peer, + domain::message::get_data const& request); + +// ----------------------------------------------------------------------------- +// Transaction Protocol +// ----------------------------------------------------------------------------- + +/// Send a transaction to peer +/// @param peer The peer session +/// @param tx Transaction to send +[[nodiscard]] +KN_API ::asio::awaitable send_transaction( + peer_session& peer, + domain::message::transaction const& tx); + +/// Request mempool contents from peer (BIP 35) +/// @param peer The peer session +[[nodiscard]] +KN_API ::asio::awaitable request_mempool( + peer_session& peer); + +// ----------------------------------------------------------------------------- +// Response Helpers (for serving peers) +// ----------------------------------------------------------------------------- + +/// Send headers in response to getheaders request +/// @param peer The peer session +/// @param headers Headers to send +[[nodiscard]] +KN_API ::asio::awaitable send_headers( + peer_session& peer, + domain::message::headers const& headers); + +/// Send a block in response to getdata request +/// @param peer The peer session +/// @param block Block to send +[[nodiscard]] +KN_API ::asio::awaitable send_block( + peer_session& peer, + domain::message::block const& block); + +/// Send not_found for items we don't have +/// @param peer The peer session +/// @param not_found Items not found +[[nodiscard]] +KN_API ::asio::awaitable send_not_found( + peer_session& peer, + domain::message::not_found const& not_found); + +// ----------------------------------------------------------------------------- +// Message Parsing Helpers +// ----------------------------------------------------------------------------- + +/// Parse a getheaders message from raw bytes +[[nodiscard]] +KN_API std::expected parse_getheaders( + raw_message const& raw, + uint32_t version); + +/// Parse a getdata message from raw bytes +[[nodiscard]] +KN_API std::expected parse_getdata( + raw_message const& raw, + uint32_t version); + +/// Parse an inventory message from raw bytes +[[nodiscard]] +KN_API std::expected parse_inventory( + raw_message const& raw, + uint32_t version); + +/// Parse a headers message from raw bytes +[[nodiscard]] +KN_API std::expected parse_headers( + raw_message const& raw, + uint32_t version); + +/// Parse a block message from raw bytes +[[nodiscard]] +KN_API std::expected parse_block( + raw_message const& raw, + uint32_t version); + +/// Parse a transaction message from raw bytes +[[nodiscard]] +KN_API std::expected parse_transaction( + raw_message const& raw, + uint32_t version); + +// ----------------------------------------------------------------------------- +// Message Loop Handler +// ----------------------------------------------------------------------------- + +/// Message handler callback type +/// Return true to continue processing, false to stop +using message_handler = std::function<::asio::awaitable(raw_message const&)>; + +/// Run a message processing loop +/// Receives messages and dispatches to handler until stopped +/// @param peer The peer session +/// @param handler Callback for each message +/// @return Error code when loop terminates +[[nodiscard]] +KN_API ::asio::awaitable run_message_loop( + peer_session& peer, + message_handler handler); + } // namespace kth::network #endif // KTH_NETWORK_PROTOCOLS_CORO_HPP diff --git a/src/network/src/handlers/ping.cpp b/src/network/src/handlers/ping.cpp new file mode 100644 index 00000000..f17c3a4b --- /dev/null +++ b/src/network/src/handlers/ping.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +namespace kth::network::handlers::ping { + +::asio::awaitable handle( + peer_session& peer, + domain::message::ping const& msg) +{ + // Respond with pong using the same nonce + domain::message::pong pong_msg(msg.nonce()); + auto ec = co_await peer.send(pong_msg); + + if (ec != error::success) { + spdlog::debug("[ping] Failed to send pong to [{}]", peer.authority()); + } else { + spdlog::debug("[ping] Responded pong to [{}]", peer.authority()); + } + + co_return message_result::handled; +} + +} // namespace kth::network::handlers::ping diff --git a/src/network/src/handlers/pong.cpp b/src/network/src/handlers/pong.cpp new file mode 100644 index 00000000..577cc33b --- /dev/null +++ b/src/network/src/handlers/pong.cpp @@ -0,0 +1,21 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +namespace kth::network::handlers::pong { + +::asio::awaitable handle( + peer_session& peer, + domain::message::pong const& msg) +{ + // Just acknowledge receipt - could verify nonce if we tracked sent pings + spdlog::trace("[pong] Received pong from [{}], nonce: {}", peer.authority(), msg.nonce()); + co_return message_result::handled; +} + +} // namespace kth::network::handlers::pong diff --git a/src/network/src/hosts.cpp b/src/network/src/hosts.cpp index c23ae544..d967df13 100644 --- a/src/network/src/hosts.cpp +++ b/src/network/src/hosts.cpp @@ -6,324 +6,218 @@ #include #include +#include #include #include + #include #include namespace kth::network { -using namespace kth::config; +namespace { + +// Check if address is IPv4-mapped in IPv6 (::ffff:x.x.x.x) +// Bitcoin protocol stores all IPs as 16-byte IPv6, with IPv4 mapped as ::ffff:x.x.x.x +// TODO(fernando): This IPv4-only filter is temporary. IPv6 addresses are being rejected +// because ASIO resolver fails with "Host not found" for many IPv6 addresses. +// Need to investigate: is it a resolver configuration issue, or are the IPv6 addresses +// from peers simply invalid/unreachable? For now, IPv4-only is faster and more reliable. +inline bool is_ipv4_mapped(infrastructure::message::ip_address const& ip) { + return ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && + ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 && + ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff; +} -#define NAME "hosts" +} // anonymous namespace -// TODO: change to network_address bimap hash table with services and age. hosts::hosts(settings const& settings) : capacity_(std::min(max_address, size_t(settings.host_pool_capacity))) - , buffer_(std::max(capacity_, size_t(1u))) - , stopped_(true) - , file_path_(settings.hosts_file) , disabled_(capacity_ == 0) -{} - -// private -hosts::iterator hosts::find(address const& host) { - auto const found = [&host](address const& entry) { - return entry.port() == host.port() && entry.ip() == host.ip(); - }; - - return std::find_if(buffer_.begin(), buffer_.end(), found); + , file_path_(settings.hosts_file) + , addresses_(capacity_ > 0 ? capacity_ : 1) +{ + if ( ! disabled_) { + load_from_file(); + } } -size_t hosts::count() const { - // Critical Section - /////////////////////////////////////////////////////////////////////////// - shared_lock lock(mutex_); - - return buffer_.size(); - /////////////////////////////////////////////////////////////////////////// +hosts::~hosts() { + if ( ! disabled_) { + save_to_file(); + } } -code hosts::fetch(address& out) const { - if (disabled_) { - return error::not_found; +void hosts::load_from_file() { + kth::ifstream file(file_path_.string()); + if (file.bad()) { + spdlog::debug("[hosts] No hosts file found or error reading."); + return; } - // Critical Section - /////////////////////////////////////////////////////////////////////////// - shared_lock lock(mutex_); + std::string line; + size_t loaded = 0; - if (stopped_) { - return error::service_stopped; - } + while (std::getline(file, line)) { + infrastructure::config::authority host(line); - if (buffer_.empty()) { - return error::not_found; + if (host.port() != 0) { + auto const addr = host.to_network_address(); + // Filter: routable + IPv4 only (for now) - TODO + if (addr.is_routable() && is_ipv4_mapped(addr.ip())) { + if (addresses_.insert(addr)) { + ++loaded; + } + } + } } - // Randomly select an address from the buffer. - auto const random = pseudo_random_broken_do_not_use::next(0, buffer_.size() - 1); - auto const index = size_t(random); - out = buffer_[index]; - return error::success; - /////////////////////////////////////////////////////////////////////////// + spdlog::debug("[hosts] Loaded {} addresses from file.", loaded); } -code hosts::fetch(address::list& out) const { - if (disabled_) { - return error::not_found; +void hosts::save_to_file() const { + kth::ofstream file(file_path_.string()); + if (file.bad()) { + spdlog::debug("[hosts] Failed to save hosts file."); + return; } - // Critical Section - /////////////////////////////////////////////////////////////////////////// - { - shared_lock lock(mutex_); + size_t saved = 0; + addresses_.cvisit_all([&](address const& addr) { + file << infrastructure::config::authority(addr) << std::endl; + ++saved; + }); - if (stopped_) { - return error::service_stopped; - } - - if (buffer_.empty()) { - return error::not_found; - } - - auto const out_count = std::min(buffer_.size(), capacity_) / size_t(pseudo_random_broken_do_not_use::next(1, 20)); - - if (out_count == 0) { - return error::success; - } - - out.reserve(out_count); - for (size_t index = 0; index < out_count; ++index) { - out.push_back(buffer_[index]); - } - } - /////////////////////////////////////////////////////////////////////////// + spdlog::debug("[hosts] Saved {} addresses to file.", saved); +} - pseudo_random_broken_do_not_use::shuffle(out); - return error::success; +size_t hosts::count() const { + return addresses_.size(); } -// load -code hosts::start() { +code hosts::fetch(address& out) const { if (disabled_) { - return error::success; + return error::not_found; } - // Critical Section - /////////////////////////////////////////////////////////////////////////// - mutex_.lock_upgrade(); - - if ( ! stopped_) { - mutex_.unlock_upgrade(); - //--------------------------------------------------------------------- - return error::operation_failed; + auto const size = addresses_.size(); + if (size == 0) { + return error::not_found; } - mutex_.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - stopped_ = false; - kth::ifstream file(file_path_.string()); - auto const file_error = file.bad(); - - if ( ! file_error) { - std::string line; + // Select a random index + auto const random_index = pseudo_random_broken_do_not_use::next(0, size - 1); - while (std::getline(file, line)) { - // TODO: create full space-delimited network_address serialization. - // Use to/from string format as opposed to wire serialization. - infrastructure::config::authority host(line); + // Visit elements to find the one at random_index + size_t current = 0; + bool found = false; - if (host.port() != 0) { - buffer_.push_back(host.to_network_address()); - } + addresses_.cvisit_all([&](address const& addr) { + if (found) return; + if (current == size_t(random_index)) { + out = addr; + found = true; } - } - - mutex_.unlock(); - /////////////////////////////////////////////////////////////////////////// + ++current; + }); - if (file_error) { - spdlog::debug("[network] Failed to save hosts file."); - return error::file_system; - } - - return error::success; + return found ? error::success : error::not_found; } -// load -code hosts::stop() { +code hosts::fetch(address::list& out, size_t requested_count) const { if (disabled_) { - return error::success; + return error::not_found; } - // Critical Section - /////////////////////////////////////////////////////////////////////////// - mutex_.lock_upgrade(); - - if (stopped_) { - mutex_.unlock_upgrade(); - //--------------------------------------------------------------------- - return error::success; + auto const size = addresses_.size(); + if (size == 0) { + return error::not_found; } - mutex_.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - stopped_ = true; - kth::ofstream file(file_path_.string()); - auto const file_error = file.bad(); + // Collect all addresses first + address::list all; + all.reserve(size); - if ( ! file_error) { - for (auto const& entry: buffer_) { - // TODO: create full space-delimited network_address serialization. - // Use to/from string format as opposed to wire serialization. - file << infrastructure::config::authority(entry) << std::endl; - } + addresses_.cvisit_all([&](address const& addr) { + all.push_back(addr); + }); - buffer_.clear(); - } - - mutex_.unlock(); - /////////////////////////////////////////////////////////////////////////// + // Shuffle and take requested count + pseudo_random_broken_do_not_use::shuffle(all); - if (file_error) { - spdlog::debug("[network] Failed to load hosts file."); - return error::file_system; + auto const take_count = std::min(requested_count, all.size()); + out.reserve(take_count); + for (size_t i = 0; i < take_count; ++i) { + out.push_back(all[i]); } return error::success; } -code hosts::remove(address const& host) { +bool hosts::remove(address const& host) { if (disabled_) { - return error::not_found; - } - - // Critical Section - /////////////////////////////////////////////////////////////////////////// - mutex_.lock_upgrade(); - - if (stopped_) { - mutex_.unlock_upgrade(); - //--------------------------------------------------------------------- - return error::service_stopped; - } - - auto it = find(host); - - if (it != buffer_.end()) { - mutex_.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - buffer_.erase(it); - - mutex_.unlock(); - //--------------------------------------------------------------------- - return error::success; + return false; } - mutex_.unlock_upgrade(); - /////////////////////////////////////////////////////////////////////////// - - return error::not_found; + return addresses_.erase(host) > 0; } -code hosts::store(address const& host) { +bool hosts::store(address const& host) { if (disabled_) { - return error::success; + return false; } - if ( ! host.is_valid()) { - // Do not treat invalid address as an error, just log it. - spdlog::debug("[network] Invalid host address from peer."); - return error::success; + // Filter non-routable addresses + if ( ! host.is_routable()) { + return false; } - // Critical Section - /////////////////////////////////////////////////////////////////////////// - mutex_.lock_upgrade(); - - if (stopped_) { - mutex_.unlock_upgrade(); - //--------------------------------------------------------------------- - return error::service_stopped; + // IPv4 only for now (see TODO above) + if ( ! is_ipv4_mapped(host.ip())) { + return false; } - if (find(host) == buffer_.end()) { - mutex_.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - buffer_.push_back(host); - - mutex_.unlock(); - //--------------------------------------------------------------------- - return error::success; + // Check capacity + if (addresses_.size() >= capacity_) { + return false; } - mutex_.unlock_upgrade(); - /////////////////////////////////////////////////////////////////////////// - - ////// We don't treat redundant address as an error, just log it. - ////spdlog::debug("[network] - ////] Redundant host address [{}] from peer.", authority(host)); - - return error::success; + return addresses_.insert(host); } -void hosts::store(address::list const& hosts, result_handler handler) { - if (disabled_ || hosts.empty()) { - handler(error::success); - return; - } - - // Critical Section - /////////////////////////////////////////////////////////////////////////// - mutex_.lock_upgrade(); - - if (stopped_) { - mutex_.unlock_upgrade(); - //--------------------------------------------------------------------- - handler(error::service_stopped); - return; +size_t hosts::store(address::list const& hosts_list) { + if (disabled_ || hosts_list.empty()) { + return 0; } - // Accept between 1 and all of this peer's addresses up to capacity. - auto const capacity = buffer_.capacity(); - auto const usable = std::min(hosts.size(), capacity); - auto const random = size_t(pseudo_random_broken_do_not_use::next(1, usable)); - - // But always accept at least the amount we are short if available. - auto const gap = capacity - buffer_.size(); - auto const accept = std::max(gap, random); - - // Convert minimum desired to step for iteration, no less than 1. - auto const step = std::max(usable / accept, size_t(1)); size_t accepted = 0; - mutex_.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - for (size_t index = 0; index < usable; index = ceiling_add(index, step)) { - auto const& host = hosts[index]; + for (auto const& host : hosts_list) { + // Filter non-routable addresses + if ( ! host.is_routable()) { + continue; + } - // Do not treat invalid address as an error, just log it. - if ( ! host.is_valid()) - { - spdlog::debug("[network] Invalid host address from peer."); + // IPv4 only for now (see TODO above) + if ( ! is_ipv4_mapped(host.ip())) { continue; } - // Do not allow duplicates in the host cache. - if (find(host) == buffer_.end()) { + // Check capacity + if (addresses_.size() >= capacity_) { + break; + } + + if (addresses_.insert(host)) { ++accepted; - buffer_.push_back(host); } } - mutex_.unlock(); - /////////////////////////////////////////////////////////////////////////// - - spdlog::debug("[network] Accepted ({} of {}) host addresses from peer.", accepted, hosts.size()); + if (accepted > 0) { + spdlog::debug("[hosts] Accepted {} of {} addresses.", accepted, hosts_list.size()); + } - handler(error::success); + return accepted; } -} // namespace kth::network \ No newline at end of file +} // namespace kth::network diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp index c126a352..fa99c15b 100644 --- a/src/network/src/p2p_node.cpp +++ b/src/network/src/p2p_node.cpp @@ -4,6 +4,9 @@ #include +#include +#include + #include #include @@ -22,7 +25,14 @@ p2p_node::p2p_node(settings const& settings) , manager_(pool_.get_executor()) , hosts_(settings) , top_block_({null_hash, 0}) -{} +{ + spdlog::debug("[p2p_node] p2p_node constructor - member init complete"); + // Register default message handlers using typed registration + // The make_handler<> wrapper handles parsing automatically + dispatcher_.register_handler(handlers::ping::handle); + dispatcher_.register_handler(handlers::pong::handle); + spdlog::debug("[p2p_node] p2p_node constructor completed successfully"); +} p2p_node::~p2p_node() { stop(); @@ -36,13 +46,7 @@ ::asio::awaitable p2p_node::start() { stopped_ = false; - // Load hosts from file - auto ec = hosts_.start(); - if (ec) { - spdlog::error("[p2p_node] Failed to load hosts: {}", ec.message()); - co_return ec; - } - + // hosts_ loads from file in constructor spdlog::info("[p2p_node] Loaded {} host addresses", hosts_.count()); // Seed if needed @@ -93,8 +97,7 @@ void p2p_node::stop() { // Stop all peers manager_.stop_all(); - // Save hosts - hosts_.stop(); + // hosts_ saves to file in destructor // Stop thread pool pool_.stop(); @@ -119,6 +122,58 @@ size_t p2p_node::connection_count() const { return manager_.count_snapshot(); } +threadpool& p2p_node::thread_pool() { + return pool_; +} + +message_dispatcher& p2p_node::dispatcher() { + return dispatcher_; +} + +// ============================================================================= +// Message Dispatcher implementation +// ============================================================================= + +::asio::awaitable message_dispatcher::dispatch(peer_session& peer, raw_message const& msg) { + auto const& command = msg.heading.command(); + + spdlog::debug("[dispatcher] Dispatching '{}' from [{}]", command, peer.authority()); + + // Look for specific handler + auto it = handlers_.find(command); + if (it != handlers_.end()) { + auto result = co_await it->second(peer, msg); + switch (result) { + case message_result::disconnect: + co_return false; + case message_result::continue_processing: + case message_result::handled: + co_return true; + case message_result::not_handled: + // Fall through to default handler + break; + } + } + + // Try default handler + if (default_handler_) { + auto result = co_await default_handler_(peer, msg); + co_return result != message_result::disconnect; + } + + // No handler - just continue + spdlog::trace("[dispatcher] Unhandled message '{}' from [{}]", command, peer.authority()); + co_return true; +} + +void message_dispatcher::register_handler(std::string const& command, message_handler_fn handler) { + handlers_[command] = std::move(handler); +} + +void message_dispatcher::set_default_handler(message_handler_fn handler) { + default_handler_ = std::move(handler); +} + infrastructure::config::checkpoint p2p_node::top_block() const { return top_block_.load(); } @@ -134,7 +189,7 @@ void p2p_node::set_top_block(infrastructure::config::checkpoint&& top) { // Manual connections // ----------------------------------------------------------------------------- -::asio::awaitable> p2p_node::connect( +awaitable_expected p2p_node::connect( std::string const& host, uint16_t port) { @@ -198,7 +253,7 @@ size_t p2p_node::address_count() const { return hosts_.count(); } -code p2p_node::store(address const& addr) { +bool p2p_node::store(address const& addr) { return hosts_.store(addr); } @@ -206,7 +261,7 @@ code p2p_node::fetch_address(address& out) const { return hosts_.fetch(out); } -code p2p_node::remove(address const& addr) { +bool p2p_node::remove(address const& addr) { return hosts_.remove(addr); } @@ -231,64 +286,177 @@ std::vector p2p_node::get_peers() const { ::asio::awaitable p2p_node::run_seeding() { spdlog::info("[p2p_node] Starting seeding from {} seeds", settings_.seeds.size()); + spdlog::debug("[p2p_node] run_seeding: before seeds check"); + + if (settings_.seeds.empty()) { + spdlog::info("[p2p_node] No seeds configured"); + co_return; + } + spdlog::debug("[p2p_node] run_seeding: getting executor"); auto executor = co_await ::asio::this_coro::executor; + spdlog::debug("[p2p_node] run_seeding: got executor"); + + // Track seeds completed + auto seeds_completed = std::make_shared>(0); + auto const total_seeds = settings_.seeds.size(); + spdlog::debug("[p2p_node] run_seeding: total_seeds = {}", total_seeds); + + // Copy seeds to avoid reference issues in coroutines + spdlog::debug("[p2p_node] run_seeding: copying seeds"); + std::vector seeds_copy( + settings_.seeds.begin(), settings_.seeds.end()); + spdlog::debug("[p2p_node] run_seeding: seeds copied, count = {}", seeds_copy.size()); - for (auto const& seed : settings_.seeds) { + // Launch seed connections in parallel + for (size_t i = 0; i < seeds_copy.size(); ++i) { if (stopped_) break; - spdlog::debug("[p2p_node] Connecting to seed {}:{}", seed.host(), seed.port()); + auto const& seed = seeds_copy[i]; + spdlog::debug("[p2p_node] run_seeding: processing seed {} of {}", i + 1, seeds_copy.size()); + + auto seed_host = seed.host(); + auto seed_port = seed.port(); + spdlog::debug("[p2p_node] run_seeding: seed {}:{}", seed_host, seed_port); + + // Use member function instead of lambda to avoid capture lifetime issues + spdlog::debug("[p2p_node] run_seeding: about to co_spawn connect_to_seed for {}:{}", seed_host, seed_port); + ::asio::co_spawn(executor, + connect_to_seed(std::move(seed_host), seed_port, seeds_completed), + ::asio::detached); + spdlog::debug("[p2p_node] run_seeding: co_spawned connect_to_seed"); + } + + spdlog::debug("[p2p_node] run_seeding: all seed tasks spawned, entering wait loop"); + + // Wait for seeds with simple timeout + auto const max_wait = std::chrono::seconds(settings_.connect_timeout_seconds + 35); + auto const start_time = std::chrono::steady_clock::now(); + + while (*seeds_completed < total_seeds && !stopped_) { + // Check elapsed time + auto elapsed = std::chrono::steady_clock::now() - start_time; + if (elapsed >= max_wait) { + spdlog::debug("[p2p_node] Seeding timeout reached"); + break; + } + + // Early exit if we have enough addresses + if (hosts_.count() >= settings_.host_pool_capacity / 4) { + spdlog::info("[p2p_node] Collected sufficient addresses, stopping seeding early"); + break; + } + + // Wait a bit before checking again + ::asio::steady_timer check_timer(executor); + check_timer.expires_after(1s); + co_await check_timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + } + + spdlog::info("[p2p_node] Seeding complete, {} addresses available", hosts_.count()); +} + +::asio::awaitable p2p_node::connect_to_seed( + std::string seed_host, + uint16_t seed_port, + std::shared_ptr> seeds_completed) +{ + spdlog::debug("[p2p_node] connect_to_seed: starting for {}:{}", seed_host, seed_port); + + auto executor = co_await ::asio::this_coro::executor; - // Use async_connect from peer_session.hpp + try { auto result = co_await async_connect( executor, - seed.host(), - seed.port(), + seed_host, + seed_port, settings_, std::chrono::seconds(settings_.connect_timeout_seconds)); if (!result) { spdlog::debug("[p2p_node] Failed to connect to seed {}:{} - {}", - seed.host(), seed.port(), result.error().message()); - continue; + seed_host, seed_port, result.error().message()); + ++(*seeds_completed); + co_return; } + spdlog::debug("[p2p_node] connect_to_seed: connected to {}:{}", seed_host, seed_port); auto peer = *result; // Start the session's message pump + spdlog::debug("[p2p_node] connect_to_seed: spawning peer->run() for {}:{}", seed_host, seed_port); ::asio::co_spawn(executor, peer->run(), ::asio::detached); // Generate nonce for handshake uint64_t nonce = generate_nonce(); // Perform handshake + spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); auto handshake_result = co_await perform_handshake(*peer, config); if (!handshake_result) { peer->stop(); spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", - seed.host(), seed.port(), handshake_result.error().message()); - continue; + seed_host, seed_port, handshake_result.error().message()); + ++(*seeds_completed); + co_return; + } + + spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); + + // Send getaddr request + auto ec = co_await peer->send(domain::message::get_address{}); + if (ec != error::success) { + peer->stop(); + ++(*seeds_completed); + co_return; } - // Request addresses - auto addr_result = co_await request_addresses(*peer, 30s); + // Wait for addr response with timeout + ::asio::steady_timer timer(executor); + timer.expires_after(30s); + bool got_addresses = false; + + while (!got_addresses && !peer->stopped()) { + auto msg_result = co_await ( + peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); - if (addr_result) { - spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", - addr_result->addresses().size(), seed.host(), seed.port()); + if (msg_result.index() == 1) { + // Timeout + break; + } - for (auto const& addr : addr_result->addresses()) { - hosts_.store(addr); + auto& [recv_ec, raw] = std::get<0>(msg_result); + if (recv_ec) { + break; + } + + if (raw.heading.command() == domain::message::address::command) { + byte_reader reader(raw.payload); + auto addr_result = domain::message::address::from_data( + reader, peer->negotiated_version()); + if (addr_result) { + auto const count = addr_result->addresses().size(); + spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", + count, seed_host, seed_port); + + for (auto const& addr : addr_result->addresses()) { + hosts_.store(addr); + } + got_addresses = true; + } } } - // Disconnect from seed peer->stop(); + } catch (std::exception const& e) { + spdlog::debug("[p2p_node] Seed {} exception: {}", seed_host, e.what()); } - spdlog::info("[p2p_node] Seeding complete, {} addresses available", hosts_.count()); + ++(*seeds_completed); } ::asio::awaitable p2p_node::run_outbound() { @@ -365,14 +533,99 @@ ::asio::awaitable p2p_node::run_inbound() { } ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { - // Run ping/pong to keep connection alive - co_await run_ping_pong(*peer, std::chrono::seconds(settings_.channel_heartbeat_minutes * 60)); + spdlog::debug("[p2p_node] Starting protocols for peer [{}]", peer->authority()); + + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer ping_timer(executor); + auto const ping_interval = std::chrono::seconds(settings_.channel_heartbeat_minutes * 60); + + spdlog::debug("[p2p_node] Ping interval for [{}]: {}s", peer->authority(), ping_interval.count()); + + while (!peer->stopped() && !stopped_) { + ping_timer.expires_after(ping_interval); + + // Wait for message or ping timer + auto result = co_await ( + peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + ping_timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (peer->stopped() || stopped_) { + break; + } + + if (result.index() == 1) { + // Timer expired - send ping + auto [timer_ec] = std::get<1>(result); + if (!timer_ec) { + uint64_t nonce = 0; + pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); + domain::message::ping ping_msg(nonce); + + auto ec = co_await peer->send(ping_msg); + if (ec != error::success) { + spdlog::debug("[p2p_node] Failed to send ping to [{}]", peer->authority()); + break; + } + spdlog::trace("[p2p_node] Sent ping to [{}]", peer->authority()); + } + continue; + } + + // Message received + auto& [ec, raw] = std::get<0>(result); + if (ec) { + break; + } + + auto const& command = raw.heading.command(); + + // Route response messages to their dedicated channels + // These are consumed by request_headers, request_block, request_addresses + // Using try_send - if channel is full or no one is waiting, message is dropped + // (this is correct behavior: unsolicited responses are ignored) + if (command == domain::message::headers::command) { + auto [send_ec] = co_await peer->headers_responses().async_send( + std::error_code{}, raw, ::asio::as_tuple(::asio::use_awaitable)); + if (!send_ec) { + continue; // Message delivered to response channel + } + // Channel full or closed - fall through to dispatcher + } else if (command == domain::message::block::command) { + auto [send_ec] = co_await peer->block_responses().async_send( + std::error_code{}, raw, ::asio::as_tuple(::asio::use_awaitable)); + if (!send_ec) { + continue; + } + } else if (command == domain::message::address::command) { + auto [send_ec] = co_await peer->addr_responses().async_send( + std::error_code{}, raw, ::asio::as_tuple(::asio::use_awaitable)); + if (!send_ec) { + continue; + } + } + + // Dispatch message through handlers + bool should_continue = co_await dispatcher_.dispatch(*peer, raw); + if (!should_continue) { + spdlog::debug("[p2p_node] Handler requested disconnect for [{}]", peer->authority()); + break; + } + } + + // Cleanup + spdlog::debug("[p2p_node] Ending protocols for peer [{}]", peer->authority()); + peer->stop(); + co_await manager_.remove(peer); } ::asio::awaitable p2p_node::maintain_outbound_connections() { auto executor = co_await ::asio::this_coro::executor; ::asio::steady_timer timer(executor); + // Maximum number of parallel connection attempts + constexpr size_t max_parallel_attempts = 8; + while (!stopped_) { auto const current_count = manager_.count_snapshot(); auto const target = settings_.outbound_connections; @@ -381,28 +634,67 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { // Need more connections auto const needed = target - current_count; - for (size_t i = 0; i < needed && !stopped_; ++i) { + // Always try max_parallel_attempts to find working peers faster + // Many addresses may be stale, so cast a wide net + auto const batch_size = max_parallel_attempts; + std::vector addresses; + addresses.reserve(batch_size); + + for (size_t i = 0; i < batch_size && !stopped_; ++i) { domain::message::network_address addr; auto ec = hosts_.fetch(addr); - if (ec) { - spdlog::debug("[p2p_node] No addresses available for outbound"); break; } + addresses.push_back(addr); + } - auto const authority = infrastructure::config::authority(addr); - auto result = co_await connect(authority.to_hostname(), authority.port()); - - if (!result) { - spdlog::debug("[p2p_node] Failed to connect to {}: {}", - authority, result.error().message()); - hosts_.remove(addr); + if (addresses.empty()) { + spdlog::debug("[p2p_node] No addresses available for outbound"); + } else { + spdlog::debug("[p2p_node] Attempting {} parallel connections (need {}, have {})", + addresses.size(), needed, current_count); + + // Launch connection attempts in parallel + std::vector<::asio::awaitable> tasks; + tasks.reserve(addresses.size()); + + // Track successful connections with a shared atomic counter + auto success_count = std::make_shared>(0); + + for (auto const& addr : addresses) { + auto task = [this, addr, success_count]() -> ::asio::awaitable { + auto const authority = infrastructure::config::authority(addr); + spdlog::trace("[p2p_node] Attempting connection to {}", authority); + + auto result = co_await connect(authority.to_hostname(), authority.port()); + + if (!result) { + spdlog::trace("[p2p_node] Connection failed to {}: {}", + authority, result.error().message()); + hosts_.remove(addr); + } else { + spdlog::debug("[p2p_node] Connected to {}", authority); + ++(*success_count); + } + }; + + // Spawn each connection attempt + ::asio::co_spawn(executor, task(), ::asio::detached); } + + // Give connection attempts time to complete + // Use a shorter wait since they're running in parallel + timer.expires_after(std::chrono::seconds(settings_.connect_timeout_seconds + 2)); + co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + + // Continue loop to check if we need more connections + continue; } } - // Wait before next check - timer.expires_after(std::chrono::seconds(settings_.connect_batch_size > 0 ? 5 : 30)); + // Wait before next check when we have enough connections + timer.expires_after(std::chrono::seconds(30)); co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); } } diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp index 1d07e9d4..aad53b6e 100644 --- a/src/network/src/peer_session.cpp +++ b/src/network/src/peer_session.cpp @@ -41,6 +41,9 @@ peer_session::peer_session(socket_type socket, settings const& settings) , strand_(socket_.get_executor()) , outbound_(strand_, 100) // Buffer up to 100 outbound messages , inbound_(strand_, 100) // Buffer up to 100 inbound messages + , headers_responses_(strand_, 10) // Response channels for request/response patterns + , block_responses_(strand_, 20) + , addr_responses_(strand_, 10) , inactivity_timer_(strand_) , expiration_timer_(strand_) , authority_(extract_authority(socket_)) @@ -54,7 +57,9 @@ peer_session::peer_session(socket_type socket, settings const& settings) , expiration_timeout_(std::chrono::minutes(settings.channel_expiration_minutes)) , version_(settings.protocol_maximum) , heading_buffer_(heading::maximum_size()) -{} +{ + spdlog::debug("[peer_session] Constructor completed, authority: {}", authority()); +} peer_session::~peer_session() { stop(error::channel_stopped); @@ -65,11 +70,15 @@ peer_session::~peer_session() { // ============================================================================= ::asio::awaitable peer_session::run() { + spdlog::debug("[peer_session] run() starting for [{}]", authority()); + if (stopped()) { + spdlog::debug("[peer_session] run() - already stopped [{}]", authority()); co_return error::channel_stopped; } stopped_ = false; + spdlog::debug("[peer_session] run() - about to start loops for [{}]", authority()); try { // Run all loops concurrently - when any completes/fails, all stop @@ -83,6 +92,7 @@ ::asio::awaitable peer_session::run() { spdlog::debug("[peer_session] Exception in run loop [{}]: {}", authority(), e.what()); } + spdlog::debug("[peer_session] run() - loops completed for [{}]", authority()); stop(error::channel_stopped); co_return error::channel_stopped; } @@ -136,6 +146,18 @@ peer_session::inbound_channel& peer_session::messages() { return inbound_; } +peer_session::response_channel& peer_session::headers_responses() { + return headers_responses_; +} + +peer_session::response_channel& peer_session::block_responses() { + return block_responses_; +} + +peer_session::response_channel& peer_session::addr_responses() { + return addr_responses_; +} + // ============================================================================= // Properties // ============================================================================= @@ -181,6 +203,7 @@ void peer_session::set_notify(bool value) { // ============================================================================= ::asio::awaitable peer_session::read_loop() { + spdlog::debug("[peer_session] read_loop() starting for [{}]", authority()); while (!stopped()) { auto result = co_await read_message(); @@ -208,6 +231,7 @@ ::asio::awaitable peer_session::read_loop() { } ::asio::awaitable peer_session::write_loop() { + spdlog::debug("[peer_session] write_loop() starting for [{}]", authority()); while (!stopped()) { auto [ec, data] = co_await outbound_.async_receive( ::asio::as_tuple(::asio::use_awaitable)); @@ -235,6 +259,7 @@ ::asio::awaitable peer_session::write_loop() { } ::asio::awaitable peer_session::inactivity_timer() { + spdlog::debug("[peer_session] inactivity_timer() starting for [{}]", authority()); while (!stopped()) { activity_signaled_ = false; inactivity_timer_.expires_after(inactivity_timeout_); @@ -261,6 +286,7 @@ ::asio::awaitable peer_session::inactivity_timer() { } ::asio::awaitable peer_session::expiration_timer() { + spdlog::debug("[peer_session] expiration_timer() starting for [{}]", authority()); expiration_timer_.expires_after(expiration_timeout_); auto [ec] = co_await expiration_timer_.async_wait( @@ -274,7 +300,7 @@ ::asio::awaitable peer_session::expiration_timer() { stop(error::channel_timeout); } -::asio::awaitable> peer_session::read_message() { +awaitable_expected peer_session::read_message() { // Read heading (24 bytes) auto [head_ec, head_bytes] = co_await ::asio::async_read( socket_, @@ -349,7 +375,7 @@ void peer_session::signal_activity() { // Connection helpers - replace connector/acceptor classes // ============================================================================= -::asio::awaitable> async_connect( +awaitable_expected async_connect( ::asio::any_io_executor executor, std::string const& hostname, uint16_t port, @@ -397,10 +423,13 @@ ::asio::awaitable> async_connect( } spdlog::debug("[async_connect] Connected to {}:{}", hostname, port); - co_return std::make_shared(std::move(socket), settings); + spdlog::debug("[async_connect] Creating peer_session..."); + auto session = std::make_shared(std::move(socket), settings); + spdlog::debug("[async_connect] peer_session created, authority: {}", session->authority()); + co_return session; } -::asio::awaitable> async_connect( +awaitable_expected async_connect( ::asio::any_io_executor executor, infrastructure::config::authority const& authority, settings const& settings, @@ -414,7 +443,7 @@ ::asio::awaitable> async_connect( timeout); } -::asio::awaitable> async_accept( +awaitable_expected async_accept( ::asio::ip::tcp::acceptor& acceptor, settings const& settings) { @@ -439,7 +468,7 @@ ::asio::awaitable> async_accept( co_return std::make_shared(std::move(socket), settings); } -::asio::awaitable> async_listen( +awaitable_expected<::asio::ip::tcp::acceptor> async_listen( ::asio::any_io_executor executor, uint16_t port) { diff --git a/src/network/src/protocols_coro.cpp b/src/network/src/protocols_coro.cpp index 415ceb81..1cd5d7b7 100644 --- a/src/network/src/protocols_coro.cpp +++ b/src/network/src/protocols_coro.cpp @@ -2,6 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +// See protocols_coro.hpp for documentation on what this file replaces. + #include #include @@ -18,7 +20,7 @@ using namespace std::chrono_literals; // Message Helpers // ============================================================================= -::asio::awaitable> wait_for_any_message( +awaitable_expected wait_for_any_message( peer_session& peer, std::chrono::seconds timeout) { @@ -121,7 +123,7 @@ bool validate_peer_version( } // anonymous namespace -::asio::awaitable> perform_handshake( +awaitable_expected perform_handshake( peer_session& peer, handshake_config const& config) { @@ -244,6 +246,9 @@ ::asio::awaitable run_ping_pong( peer_session& peer, std::chrono::seconds ping_interval) { + spdlog::trace("[protocol] Starting ping/pong loop for [{}] with interval {}s", + peer.authority(), ping_interval.count()); + auto executor = co_await ::asio::this_coro::executor; ::asio::steady_timer ping_timer(executor); @@ -277,7 +282,7 @@ ::asio::awaitable run_ping_pong( co_return ec; } - spdlog::trace("[protocol] Sent ping to [{}] nonce={}", peer.authority(), last_ping_nonce); + spdlog::trace("[protocol] Sent ping to [{}]", peer.authority()); } } else { @@ -307,8 +312,7 @@ ::asio::awaitable run_ping_pong( byte_reader pong_reader(raw.payload); auto pong_result = domain::message::pong::from_data(pong_reader, peer.negotiated_version()); if (pong_result) { - spdlog::trace("[protocol] Received pong from [{}] nonce={}", - peer.authority(), pong_result->nonce()); + spdlog::trace("[protocol] Received pong from [{}]", peer.authority()); } } // Other messages are ignored by this protocol @@ -322,7 +326,7 @@ ::asio::awaitable run_ping_pong( // Address Protocol // ============================================================================= -::asio::awaitable> request_addresses( +awaitable_expected request_addresses( peer_session& peer, std::chrono::seconds timeout) { @@ -332,7 +336,162 @@ ::asio::awaitable> request_address co_return std::unexpected(ec); } - // Wait for addr response + // Wait for addr response on the dedicated channel + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor, timeout); + + auto result = co_await ( + peer.addr_responses().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + co_return std::unexpected(error::channel_timeout); + } + + auto& [recv_ec, raw] = std::get<0>(result); + if (recv_ec) { + co_return std::unexpected(error::channel_stopped); + } + + // Parse the address message + byte_reader reader(raw.payload); + auto addr_result = domain::message::address::from_data(reader, peer.negotiated_version()); + if (!addr_result) { + co_return std::unexpected(error::bad_stream); + } + + co_return std::move(*addr_result); +} + +::asio::awaitable send_addresses( + peer_session& peer, + domain::message::address const& addresses) +{ + co_return co_await peer.send(addresses); +} + +// ============================================================================= +// Blockchain Protocol Handlers +// ============================================================================= + +// ----------------------------------------------------------------------------- +// Header Sync Protocol +// ----------------------------------------------------------------------------- + +awaitable_expected request_headers( + peer_session& peer, + hash_list const& locator_hashes, + hash_digest const& stop_hash, + std::chrono::seconds timeout) +{ + // Build getheaders message + domain::message::get_headers request(locator_hashes, stop_hash); + + spdlog::debug("[protocol] Requesting headers from [{}] with {} locator hashes", + peer.authority(), locator_hashes.size()); + + // Send getheaders + auto ec = co_await peer.send(request); + if (ec != error::success) { + spdlog::debug("[protocol] Failed to send getheaders to [{}]", peer.authority()); + co_return std::unexpected(ec); + } + + // Wait for headers response on the dedicated channel + // The message dispatcher routes 'headers' messages to this channel + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor, timeout); + + auto result = co_await ( + peer.headers_responses().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + spdlog::debug("[protocol] Timeout waiting for headers from [{}]", peer.authority()); + co_return std::unexpected(error::channel_timeout); + } + + auto& [recv_ec, raw] = std::get<0>(result); + if (recv_ec) { + spdlog::debug("[protocol] Channel error waiting for headers from [{}]", peer.authority()); + co_return std::unexpected(error::channel_stopped); + } + + // Parse the headers message + byte_reader reader(raw.payload); + auto headers_result = domain::message::headers::from_data(reader, peer.negotiated_version()); + if (!headers_result) { + spdlog::debug("[protocol] Failed to parse headers from [{}]", peer.authority()); + co_return std::unexpected(error::bad_stream); + } + + spdlog::debug("[protocol] Received {} headers from [{}]", + headers_result->elements().size(), peer.authority()); + + co_return std::move(*headers_result); +} + +awaitable_expected request_headers_from( + peer_session& peer, + hash_digest const& from_hash, + std::chrono::seconds timeout) +{ + hash_list locator{from_hash}; + co_return co_await request_headers(peer, locator, null_hash, timeout); +} + +// ----------------------------------------------------------------------------- +// Block Sync Protocol +// ----------------------------------------------------------------------------- + +::asio::awaitable request_blocks( + peer_session& peer, + hash_list const& block_hashes) +{ + if (block_hashes.empty()) { + co_return error::success; + } + + // Build inventory for block request + domain::message::inventory_vector::list inventories; + inventories.reserve(block_hashes.size()); + + for (auto const& hash : block_hashes) { + inventories.emplace_back(domain::message::inventory_vector::type_id::block, hash); + } + + domain::message::get_data request(std::move(inventories)); + + spdlog::debug("[protocol] Requesting {} blocks from [{}]", + block_hashes.size(), peer.authority()); + + // Send getdata - blocks will arrive asynchronously + co_return co_await peer.send(request); +} + +awaitable_expected request_block( + peer_session& peer, + hash_digest const& block_hash, + std::chrono::seconds timeout) +{ + // Build single-block getdata + domain::message::inventory_vector::list inventories{ + {domain::message::inventory_vector::type_id::block, block_hash} + }; + domain::message::get_data request(std::move(inventories)); + + spdlog::debug("[protocol] Requesting block {} from [{}]", + encode_hash(block_hash), peer.authority()); + + auto ec = co_await peer.send(request); + if (ec != error::success) { + co_return std::unexpected(ec); + } + + // Wait for block response on the dedicated channel + auto executor = co_await ::asio::this_coro::executor; auto deadline = std::chrono::steady_clock::now() + timeout; while (true) { @@ -340,32 +499,250 @@ ::asio::awaitable> request_address deadline - std::chrono::steady_clock::now()); if (remaining <= 0s) { + spdlog::debug("[protocol] Timeout waiting for block from [{}]", peer.authority()); co_return std::unexpected(error::channel_timeout); } - auto msg_result = co_await wait_for_any_message(peer, remaining); - if (!msg_result) { - co_return std::unexpected(msg_result.error()); + ::asio::steady_timer timer(executor, remaining); + + auto result = co_await ( + peer.block_responses().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + spdlog::debug("[protocol] Timeout waiting for block from [{}]", peer.authority()); + co_return std::unexpected(error::channel_timeout); } - auto const& raw = *msg_result; - if (raw.heading.command() == domain::message::address::command) { - byte_reader reader(raw.payload); - auto addr_result = domain::message::address::from_data(reader, peer.negotiated_version()); - if (!addr_result) { - co_return std::unexpected(error::bad_stream); - } - co_return std::move(*addr_result); + auto& [recv_ec, raw] = std::get<0>(result); + if (recv_ec) { + co_return std::unexpected(error::channel_stopped); + } + + // Parse the block + byte_reader reader(raw.payload); + auto block_result = domain::message::block::from_data(reader, peer.negotiated_version()); + if (!block_result) { + spdlog::debug("[protocol] Failed to parse block from [{}]", peer.authority()); + co_return std::unexpected(error::bad_stream); } - // Continue waiting for addr message + + // Verify it's the block we requested + if (block_result->header().hash() != block_hash) { + spdlog::debug("[protocol] Received unexpected block from [{}]", peer.authority()); + // Continue waiting for the correct block + continue; + } + + spdlog::debug("[protocol] Received block {} from [{}]", + encode_hash(block_hash), peer.authority()); + + co_return std::move(*block_result); } } -::asio::awaitable send_addresses( +// ----------------------------------------------------------------------------- +// Inventory Protocol +// ----------------------------------------------------------------------------- + +::asio::awaitable send_inventory( peer_session& peer, - domain::message::address const& addresses) + domain::message::inventory const& inv) { - co_return co_await peer.send(addresses); + spdlog::trace("[protocol] Sending {} inventory items to [{}]", + inv.inventories().size(), peer.authority()); + co_return co_await peer.send(inv); +} + +::asio::awaitable send_getdata( + peer_session& peer, + domain::message::get_data const& request) +{ + spdlog::trace("[protocol] Sending getdata for {} items to [{}]", + request.inventories().size(), peer.authority()); + co_return co_await peer.send(request); +} + +// ----------------------------------------------------------------------------- +// Transaction Protocol +// ----------------------------------------------------------------------------- + +::asio::awaitable send_transaction( + peer_session& peer, + domain::message::transaction const& tx) +{ + spdlog::debug("[protocol] Sending transaction {} to [{}]", + encode_hash(tx.hash()), peer.authority()); + co_return co_await peer.send(tx); +} + +::asio::awaitable request_mempool( + peer_session& peer) +{ + spdlog::debug("[protocol] Requesting mempool from [{}]", peer.authority()); + co_return co_await peer.send(domain::message::memory_pool{}); +} + +// ----------------------------------------------------------------------------- +// Response Helpers (for serving peers) +// ----------------------------------------------------------------------------- + +::asio::awaitable send_headers( + peer_session& peer, + domain::message::headers const& headers) +{ + spdlog::trace("[protocol] Sending {} headers to [{}]", + headers.elements().size(), peer.authority()); + co_return co_await peer.send(headers); +} + +::asio::awaitable send_block( + peer_session& peer, + domain::message::block const& block) +{ + spdlog::trace("[protocol] Sending block {} to [{}]", + encode_hash(block.header().hash()), peer.authority()); + co_return co_await peer.send(block); +} + +::asio::awaitable send_not_found( + peer_session& peer, + domain::message::not_found const& not_found) +{ + spdlog::trace("[protocol] Sending not_found for {} items to [{}]", + not_found.inventories().size(), peer.authority()); + co_return co_await peer.send(not_found); +} + +// ----------------------------------------------------------------------------- +// Message Parsing Helpers +// ----------------------------------------------------------------------------- +// TODO(fernando): Consider making these generic with a single template function: +// template +// std::expected parse_message(raw_message const&, uint32_t version); +// +// TODO(fernando): These functions may be replaced by make_handler() from +// p2p_node.hpp if we move to a fully handler-based architecture. For now, these +// are useful for request/response protocols where we wait for specific messages. +// ----------------------------------------------------------------------------- + +std::expected parse_getheaders( + raw_message const& raw, + uint32_t version) +{ + if (raw.heading.command() != domain::message::get_headers::command) { + return std::unexpected(error::bad_stream); + } + byte_reader reader(raw.payload); + auto result = domain::message::get_headers::from_data(reader, version); + if (!result) { + return std::unexpected(error::bad_stream); + } + return std::move(*result); +} + +std::expected parse_getdata( + raw_message const& raw, + uint32_t version) +{ + if (raw.heading.command() != domain::message::get_data::command) { + return std::unexpected(error::bad_stream); + } + byte_reader reader(raw.payload); + auto result = domain::message::get_data::from_data(reader, version); + if (!result) { + return std::unexpected(error::bad_stream); + } + return std::move(*result); +} + +std::expected parse_inventory( + raw_message const& raw, + uint32_t version) +{ + if (raw.heading.command() != domain::message::inventory::command) { + return std::unexpected(error::bad_stream); + } + byte_reader reader(raw.payload); + auto result = domain::message::inventory::from_data(reader, version); + if (!result) { + return std::unexpected(error::bad_stream); + } + return std::move(*result); +} + +std::expected parse_headers( + raw_message const& raw, + uint32_t version) +{ + if (raw.heading.command() != domain::message::headers::command) { + return std::unexpected(error::bad_stream); + } + byte_reader reader(raw.payload); + auto result = domain::message::headers::from_data(reader, version); + if (!result) { + return std::unexpected(error::bad_stream); + } + return std::move(*result); +} + +std::expected parse_block( + raw_message const& raw, + uint32_t version) +{ + if (raw.heading.command() != domain::message::block::command) { + return std::unexpected(error::bad_stream); + } + byte_reader reader(raw.payload); + auto result = domain::message::block::from_data(reader, version); + if (!result) { + return std::unexpected(error::bad_stream); + } + return std::move(*result); +} + +std::expected parse_transaction( + raw_message const& raw, + [[maybe_unused]] uint32_t version) +{ + if (raw.heading.command() != domain::message::transaction::command) { + return std::unexpected(error::bad_stream); + } + byte_reader reader(raw.payload); + auto result = domain::message::transaction::from_data(reader, true); + if (!result) { + return std::unexpected(error::bad_stream); + } + return std::move(*result); +} + +// ----------------------------------------------------------------------------- +// Message Loop Handler +// ----------------------------------------------------------------------------- + +::asio::awaitable run_message_loop( + peer_session& peer, + message_handler handler) +{ + while (!peer.stopped()) { + // Wait for next message (no timeout - runs until stopped) + auto result = co_await peer.messages().async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + auto& [ec, raw] = result; + if (ec) { + co_return error::channel_stopped; + } + + // Dispatch to handler + bool continue_loop = co_await handler(raw); + if (!continue_loop) { + break; + } + } + + co_return error::channel_stopped; } } // namespace kth::network diff --git a/src/node-exe/CMakeLists.txt b/src/node-exe/CMakeLists.txt index 00e52b17..40bbbf95 100644 --- a/src/node-exe/CMakeLists.txt +++ b/src/node-exe/CMakeLists.txt @@ -93,13 +93,24 @@ endif() # Build # ------------------------------------------------------------------------------ -add_executable(${PROJECT_NAME} src/main.cpp) +add_executable(${PROJECT_NAME} + src/main.cpp + src/tui_dashboard.cpp +) set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX CXX_STANDARD 23 CXX_STANDARD_REQUIRED TRUE) # Note: These should be inherited from node::node target via Conan # target_compile_definitions(${PROJECT_NAME} PUBLIC -DKND_STATIC -DKB_STATIC -DKN_STATIC) -target_link_libraries(${PROJECT_NAME} PUBLIC node::node) +# Find FTXUI for TUI dashboard +find_package(ftxui REQUIRED) + +target_link_libraries(${PROJECT_NAME} PUBLIC + node::node + ftxui::screen + ftxui::dom + ftxui::component +) if (MINGW) target_link_libraries(${PROJECT_NAME} PUBLIC ws2_32 wsock32) diff --git a/src/node-exe/conanfile.py b/src/node-exe/conanfile.py deleted file mode 100644 index 9c1b7d69..00000000 --- a/src/node-exe/conanfile.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" - -class KnuthNodeExeConan(KnuthConanFileV2): - name = "kth" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/kth" - description = "Bitcoin full node executable" - settings = "os", "compiler", "build_type", "arch" - package_type = "application" - - options = { - "currency": ['BCH', 'BTC', 'LTC'], - "no_compilation": [True, False], - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - "verbose": [True, False], - "mempool": [True, False], - "db": ['dynamic'], - "db_readonly": [True, False], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - "statistics": [True, False], - } - - default_options = { - "currency": "BCH", - "no_compilation": False, - "march_strategy": "download_if_possible", - "verbose": False, - "mempool": False, - "db": "dynamic", - "db_readonly": False, - "cmake_export_compile_commands": False, - "statistics": False, - } - - exports_sources = "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "src/*" - - def _is_legacy_db(self): - return self.options.db == "legacy" or self.options.db == "legacy_full" - - def dont_compile(self, options, settings): - return options.no_compilation or (settings.compiler == None and settings.arch == 'x86_64' and settings.os in ('Linux', 'Windows', 'Macos')) - - def requirements(self): - if not self.options.no_compilation and self.settings.get_safe("compiler") is not None: - self.requires("node/0.58.0", transitive_headers=True, transitive_libs=True) - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - # if self.options.no_compilation or (self.settings.compiler == None and self.settings.arch == 'x86_64' and self.settings.os in ('Linux', 'Windows', 'Macos')): - if self.dont_compile(self.options, self.settings): - self.settings.remove("compiler") - self.settings.remove("build_type") - - self.options["*"].db_readonly = self.options.db_readonly - self.output.info("Compiling with read-only DB: %s" % (self.options.db_readonly,)) - - self.options["*"].mempool = self.options.mempool - self.output.info("Compiling with mempool: %s" % (self.options.mempool,)) - - self.options["*"].statistics = self.options.statistics - self.output.info("Compiling with statistics: %s" % (self.options.statistics,)) - - def package_id(self): - KnuthConanFileV2.package_id(self) - - if self.dont_compile(self.info.options, self.info.settings): - self.info.requires.clear() - - # self.output.info("package_id - self.channel: %s" % (self.channel,)) - # self.output.info("package_id - self.options.no_compilation: %s" % (self.options.no_compilation,)) - # self.output.info("package_id - self.settings.compiler: %s" % (self.settings.compiler,)) - # self.output.info("package_id - self.settings.arch: %s" % (self.settings.arch,)) - # self.output.info("package_id - self.settings.os: %s" % (self.settings.os,)) - # self.output.info("package_id - is_development_branch_internal: %s" % (is_development_branch_internal(self.channel),)) - - # if not is_development_branch_internal(self.channel): - # self.info.settings.compiler = "ANY" - # self.info.settings.build_type = "ANY" - self.info.settings.compiler = "ANY" - self.info.settings.build_type = "ANY" - - self.info.options.no_compilation = "ANY" - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - tc.variables["WITH_MEMPOOL"] = option_on_off(self.options.mempool) - tc.variables["DB_READONLY_MODE"] = option_on_off(self.options.db_readonly) - tc.variables["STATISTICS"] = option_on_off(self.options.statistics) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - if not self.options.cmake_export_compile_commands: - cmake.build() - # if self.options.tests: - # cmake.test() - - - def package(self): - cmake = CMake(self) - cmake.install() - - # def package(self): - # self.copy("kth.exe", dst="bin", src="bin") # Windows - # self.copy("kth", dst="bin", src="bin") # Unixes - - def deploy(self): - self.copy("kth.exe", src="bin") # copy from current package - self.copy("kth", src="bin") # copy from current package - # self.copy_deps("*.dll") # copy from dependencies diff --git a/src/node-exe/src/main.cpp b/src/node-exe/src/main.cpp index d101073b..e762668d 100644 --- a/src/node-exe/src/main.cpp +++ b/src/node-exe/src/main.cpp @@ -3,16 +3,23 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include + #include -#include +#include #include +#include +#include #include +#include #include #include #include #include +#include "version.hpp" +#include "tui_dashboard.hpp" + KTH_USE_MAIN static auto const application_name = "kth"; @@ -35,7 +42,8 @@ void do_settings(kth::node::parser& metadata, std::ostream& output) { print.settings(output); } -bool run(kth::node::executor& host) { +bool run_with_log(kth::node::executor& host) { + // Traditional log mode - scrolling output return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { if (ec != kth::error::success) { host.signal_stop(); @@ -43,6 +51,85 @@ bool run(kth::node::executor& host) { }); } +bool run_with_tui(kth::node::executor& host) { + // TUI dashboard mode + std::unique_ptr dashboard; + try { + dashboard = kth::node_exe::make_tui_dashboard(); + } catch (std::exception const& e) { + std::cerr << "Failed to create TUI dashboard: " << e.what() << std::endl; + return run_with_log(host); // Fallback to log mode + } + + // Set initial status + kth::node_exe::node_status status; + status.version = KTH_NODE_VERSION; + status.network_name = "BCH Mainnet"; // TODO: get from config + status.state = kth::node_exe::node_status::sync_state::starting; + status.start_time = std::chrono::system_clock::now(); // Initialize start time + dashboard->update_status(status); + + // Start TUI + try { + dashboard->start(); + } catch (std::exception const& e) { + std::cerr << "Failed to start TUI: " << e.what() << std::endl; + return run_with_log(host); // Fallback to log mode + } + + // Run node (non-blocking) + bool init_ok = host.init_run(version(), kth::node::start_modules::all, [&host, &dashboard, &status](std::error_code const& ec) { + if (ec != kth::error::success) { + status.state = kth::node_exe::node_status::sync_state::error; + dashboard->update_status(status); + dashboard->request_exit(); // Signal TUI to exit on error + } + }); + + if (!init_ok) { + dashboard->stop(); + return false; + } + + // TODO(fernando): Update dashboard periodically with node status + // This would be done via a callback mechanism from the node + + // Wait for TUI exit (user pressed q or ESC, or node error) + while (dashboard->is_running()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + // Stop node if TUI exited + if (!host.stopped()) { + host.signal_stop(); + } + + dashboard->stop(); + return host.close(); +} + +bool run_daemon(kth::node::executor& host) { + // Daemon mode - minimal output, suitable for systemd + return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { + if (ec != kth::error::success) { + host.signal_stop(); + } + }); +} + +bool run(kth::node::executor& host, kth::display_mode mode) { + switch (mode) { + case kth::display_mode::tui: + return run_with_tui(host); + case kth::display_mode::log: + return run_with_log(host); + case kth::display_mode::daemon: + return run_daemon(host); + default: + return run_with_tui(host); + } +} + bool menu(kth::node::parser& metadata, kth::node::executor& host, std::ostream& output) { auto const& config = metadata.configured; @@ -74,8 +161,8 @@ bool menu(kth::node::parser& metadata, kth::node::executor& host, std::ostream& } #endif // ! defined(KTH_DB_READONLY) - // There are no command line arguments, just run the node. - return run(host); + // Run the node with the configured display mode + return run(host, config.node.display); } int kth::main(int argc, char* argv[]) { @@ -91,7 +178,9 @@ int kth::main(int argc, char* argv[]) { return console_result::failure; } - // executor host(metadata.configured, cout, cerr); - executor host(metadata.configured, true); + // Only enable stdout logging in "log" mode + // TUI and daemon modes should only log to files + bool const stdout_enabled = (metadata.configured.node.display == display_mode::log); + executor host(metadata.configured, stdout_enabled); return menu(metadata, host, cout) ? console_result::okay : console_result::failure; } diff --git a/src/node-exe/src/tui_dashboard.cpp b/src/node-exe/src/tui_dashboard.cpp new file mode 100644 index 00000000..72ceab59 --- /dev/null +++ b/src/node-exe/src/tui_dashboard.cpp @@ -0,0 +1,1139 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "tui_dashboard.hpp" + +#include +#include +#include + +namespace kth::node_exe { + +using namespace ftxui; + +// Color palette - Knuth purple + BCH green theme +namespace colors { + // Knuth brand colors (purple/violet) + auto const kth_purple = Color::RGB(75, 0, 130); + auto const kth_violet = Color::RGB(100, 50, 180); + auto const kth_light = Color::RGB(140, 100, 200); + + // BCH green + auto const bch_green = Color::RGB(10, 193, 142); + auto const bch_light = Color::RGB(78, 215, 175); + + // Standard colors + auto const green = Color::RGB(76, 175, 80); + auto const red = Color::RGB(244, 67, 54); + auto const orange = Color::RGB(255, 152, 0); + auto const blue = Color::RGB(33, 150, 243); + auto const cyan = Color::RGB(0, 188, 212); + auto const yellow = Color::RGB(255, 235, 59); + auto const white = Color::RGB(255, 255, 255); + auto const gray = Color::RGB(158, 158, 158); + auto const dark_gray = Color::RGB(97, 97, 97); +} + +// ASCII art logo lines (from executor::print_ascii_art) +static std::vector const logo_lines = { + R"( ... )", + R"( .-=*#%%= :-=+++*#:)", + R"( :+*%%%@= .:--#@@#.)", + R"( :%%@= .:. :%@#. )", + R"( .%%@= .*%%- :#@%: )", + R"( :%%@= .. .#@%= .#@%- )", + R"( :%%@= .=###**+. -+++#%%%***. +@%= :=+*+-)", + R"( :%%%- :%%=:. :--%@%*-::. =%%= -+*=-%@@=)", + R"( :%%%: :*+. .::. =%@*. :%@#:++: +@@+)", + R"( :%%%*+#: .#%%%= -%@#. .*%%%*: *%@-)", + R"( -%%%@@%*- :#@@%= :#@#. +@%%+ :%%%.)", + R"( =@%%-+%@%+. .-=- .#@%:.=*. -%%%- .#@%- )", + R"( -@%%. :*%@#- .*@%+=#%- :%@#: .-- .*@%- )", + R"( .:*@%%: =%@@*-. +@%%@%+. .*@#. *@@*=#@#: )", + R"( .*#####*: -*#####*. *%%*=. .**: :*#%#+-. )", + R"( ........ .. .... ... .. )", +}; + +static std::string const slogan = "High Performance Bitcoin Cash Node"; + +tui_dashboard::tui_dashboard() { + status_.start_time = std::chrono::system_clock::now(); + splash_start_ = std::chrono::steady_clock::now(); + + // Define navigable screens (after splash) + navigable_screens_ = { + screen_id::dashboard, + screen_id::network, + screen_id::blockchain, + screen_id::mempool, + screen_id::logs, + screen_id::terminal, + }; + + // Initialize terminal with welcome message + terminal_history_.push_back(""); + terminal_history_.push_back(" **** KNUTH 64 BASIC V2 ****"); + terminal_history_.push_back(""); + terminal_history_.push_back(" 64K RAM SYSTEM 38911 BASIC BYTES FREE"); + terminal_history_.push_back(""); + terminal_history_.push_back("READY."); +} + +tui_dashboard::~tui_dashboard() { + stop(); +} + +void tui_dashboard::start() { + if (running_.exchange(true)) { + return; + } + + ui_thread_ = std::thread([this] { + auto screen = ScreenInteractive::Fullscreen(); + screen_.store(&screen); + + auto renderer = Renderer([this] { + return render(); + }); + + // Refresh for animations (60fps during splash, 2fps after) + std::atomic refresh_ui_continue{true}; + std::thread refresh_ui([&] { + while (refresh_ui_continue && !exit_requested_) { + auto delay = (current_screen_ == screen_id::splash) ? + std::chrono::milliseconds(50) : // Fast for animation + std::chrono::milliseconds(500); // Slow for dashboard + std::this_thread::sleep_for(delay); + screen.PostEvent(Event::Custom); + } + }); + + // Handle input events + auto component = CatchEvent(renderer, [&](Event event) { + if (exit_requested_) { + screen.Exit(); + return true; + } + + // Handle goodbye screen - exit after delay + if (show_goodbye_) { + auto elapsed = std::chrono::duration_cast( + std::chrono::steady_clock::now() - goodbye_start_).count(); + if (elapsed > 2000) { // 2 seconds goodbye + exit_requested_ = true; + screen.Exit(); + } + return true; // Block all events during goodbye + } + + // Handle exit confirmation dialog + if (show_exit_confirm_) { + if (event == Event::Character('y') || event == Event::Character('Y') || event == Event::Return) { + show_exit_confirm_ = false; + show_goodbye_ = true; + goodbye_start_ = std::chrono::steady_clock::now(); + return true; + } + if (event == Event::Character('n') || event == Event::Character('N') || event == Event::Escape) { + show_exit_confirm_ = false; + return true; + } + return true; // Block other events while dialog is shown + } + + // Skip splash on any key + if (current_screen_ == screen_id::splash && !splash_complete_) { + if (event.is_character() || event == Event::Return || + event == Event::Escape || event == Event::ArrowLeft || + event == Event::ArrowRight) { + splash_complete_ = true; + current_screen_ = screen_id::dashboard; + return true; + } + } + + // Terminal input handling + if (current_screen_ == screen_id::terminal) { + // Only ESC exits from terminal (not Q, since we need to type) + if (event == Event::Escape) { + show_exit_confirm_ = true; + return true; + } + // Enter - process command + if (event == Event::Return) { + terminal_process_command(); + return true; + } + // Backspace + if (event == Event::Backspace && !terminal_input_.empty()) { + terminal_input_.pop_back(); + return true; + } + // Character input (convert to uppercase like C64) + if (event.is_character()) { + char c = event.character()[0]; + if (c >= 'a' && c <= 'z') { + c = c - 'a' + 'A'; // Uppercase + } + terminal_input_ += c; + return true; + } + // Arrow keys still work for navigation + if (event == Event::ArrowRight) { + next_screen(); + return true; + } + if (event == Event::ArrowLeft) { + prev_screen(); + return true; + } + return false; + } + + // Show exit confirmation (not in terminal mode) + if (event == Event::Character('q') || event == Event::Character('Q') || event == Event::Escape) { + show_exit_confirm_ = true; + return true; + } + + // Navigation (only after splash) + if (current_screen_ != screen_id::splash) { + if (event == Event::ArrowRight || event == Event::Character('l')) { + next_screen(); + return true; + } + if (event == Event::ArrowLeft || event == Event::Character('h')) { + prev_screen(); + return true; + } + } + + return false; + }); + + screen.Loop(component); + + refresh_ui_continue = false; + if (refresh_ui.joinable()) { + refresh_ui.join(); + } + + screen_.store(nullptr); + running_ = false; + }); +} + +void tui_dashboard::stop() { + exit_requested_ = true; + if (ui_thread_.joinable()) { + ui_thread_.join(); + } +} + +void tui_dashboard::update_status(node_status const& status) { + { + std::lock_guard lock(status_mutex_); + status_ = status; + } + auto* scr = screen_.load(); + if (scr != nullptr) { + scr->PostEvent(Event::Custom); + } +} + +bool tui_dashboard::is_running() const { + return running_; +} + +void tui_dashboard::request_exit() { + exit_requested_ = true; + auto* scr = screen_.load(); + if (scr != nullptr) { + scr->PostEvent(Event::Custom); + } +} + +void tui_dashboard::next_screen() { + auto it = std::find(navigable_screens_.begin(), navigable_screens_.end(), current_screen_); + if (it != navigable_screens_.end()) { + ++it; + if (it == navigable_screens_.end()) { + it = navigable_screens_.begin(); + } + current_screen_ = *it; + } +} + +void tui_dashboard::prev_screen() { + auto it = std::find(navigable_screens_.begin(), navigable_screens_.end(), current_screen_); + if (it != navigable_screens_.end()) { + if (it == navigable_screens_.begin()) { + it = navigable_screens_.end(); + } + --it; + current_screen_ = *it; + } +} + +Element tui_dashboard::render() { + std::lock_guard lock(status_mutex_); + + Element screen_content; + switch (current_screen_) { + case screen_id::splash: + screen_content = render_splash(); + break; + case screen_id::dashboard: + screen_content = render_dashboard(); + break; + case screen_id::network: + screen_content = render_network_screen(); + break; + case screen_id::blockchain: + screen_content = render_blockchain_screen(); + break; + case screen_id::mempool: + screen_content = render_mempool_screen(); + break; + case screen_id::logs: + screen_content = render_logs_screen(); + break; + case screen_id::terminal: + screen_content = render_terminal_screen(); + break; + default: + screen_content = render_dashboard(); + break; + } + + // Show goodbye screen + if (show_goodbye_) { + return vbox({ + filler(), + hbox({ + filler(), + vbox({ + text("") , + text(" ╔═══════════════════════════════════════╗ ") | color(colors::kth_violet), + text(" ║ ║ ") | color(colors::kth_violet), + text(" ║ Goodbye! ║ ") | color(colors::bch_green) | bold, + text(" ║ ║ ") | color(colors::kth_violet), + text(" ║ Thanks for using Knuth Node ║ ") | color(colors::white), + text(" ║ ║ ") | color(colors::kth_violet), + text(" ║ kth.cash ║ ") | color(colors::kth_light), + text(" ║ ║ ") | color(colors::kth_violet), + text(" ╚═══════════════════════════════════════╝ ") | color(colors::kth_violet), + text(""), + }), + filler(), + }), + filler(), + }) | border | color(colors::kth_purple); + } + + // Show exit confirmation dialog if requested + if (show_exit_confirm_) { + auto dialog = vbox({ + text(""), + hbox({ + filler(), + vbox({ + text("┌───────────────────────────────────┐") | color(colors::kth_violet), + text("│ │") | color(colors::kth_violet), + text("│ Are you sure you want to exit? │") | color(colors::white) | bold, + text("│ │") | color(colors::kth_violet), + hbox({ + text("│ ") | color(colors::kth_violet), + text("[Y]") | color(colors::bch_green) | bold, + text(" Yes ") | color(colors::gray), + text("[N]") | color(colors::red) | bold, + text(" No │") | color(colors::gray), + }), + text("│ │") | color(colors::kth_violet), + text("└───────────────────────────────────┘") | color(colors::kth_violet), + }), + filler(), + }), + text(""), + }); + + return dbox({ + screen_content | dim, + filler(), + dialog | center, + }); + } + + return screen_content; +} + +Element tui_dashboard::render_splash() { + auto now = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(now - splash_start_).count(); + + // Animation timing (80s style typewriter effect) + int const char_delay_ms = 3; // Time per character (fast) + int const line_delay_ms = 30; // Extra delay per line + int const slogan_delay_ms = 300; // Delay before slogan + int const hold_delay_ms = 3500; // Hold splash after animation + int const total_chars = [&] { + int c = 0; + for (auto const& line : logo_lines) c += line.size(); + return c; + }(); + int const logo_duration = total_chars * char_delay_ms + logo_lines.size() * line_delay_ms; + int const total_duration = logo_duration + slogan_delay_ms + slogan.size() * char_delay_ms + hold_delay_ms; + + // Check if animation complete + if (elapsed > total_duration) { + splash_complete_ = true; + current_screen_ = screen_id::dashboard; + return render_dashboard(); + } + + Elements logo_elements; + int chars_shown = 0; + int time_cursor = 0; + + // Render logo with typewriter effect + for (size_t i = 0; i < logo_lines.size(); ++i) { + auto const& line = logo_lines[i]; + int line_start_time = time_cursor; + int line_end_time = line_start_time + line.size() * char_delay_ms; + + if (elapsed < line_start_time) { + // Line not started yet + break; + } + + int visible_chars = std::min( + static_cast(line.size()), + static_cast((elapsed - line_start_time) / char_delay_ms) + ); + + std::string visible_text = line.substr(0, visible_chars); + + // Color gradient based on line position + Color line_color; + float t = static_cast(i) / logo_lines.size(); + if (t < 0.3f) { + line_color = colors::kth_light; + } else if (t < 0.7f) { + line_color = colors::kth_violet; + } else { + line_color = colors::kth_purple; + } + + // Add blinking cursor at end if still typing this line + if (visible_chars < static_cast(line.size()) && (elapsed / 100) % 2 == 0) { + visible_text += "█"; + } + + logo_elements.push_back(text(visible_text) | color(line_color) | bold); + + time_cursor = line_end_time + line_delay_ms; + } + + // Slogan with typewriter effect + Element slogan_element = text(""); + int slogan_start = logo_duration + slogan_delay_ms; + if (elapsed > slogan_start) { + int slogan_elapsed = elapsed - slogan_start; + int visible_chars = std::min( + static_cast(slogan.size()), + slogan_elapsed / char_delay_ms + ); + std::string visible_slogan = slogan.substr(0, visible_chars); + + // Blinking cursor + if (visible_chars < static_cast(slogan.size()) && (elapsed / 100) % 2 == 0) { + visible_slogan += "█"; + } + + slogan_element = text(visible_slogan) | color(colors::bch_green) | bold; + } + + // Decorative elements - 80s style + std::string border_char = "═"; + int border_pulse = (elapsed / 200) % 4; + Color border_color = (border_pulse == 0) ? colors::kth_purple : + (border_pulse == 1) ? colors::kth_violet : + (border_pulse == 2) ? colors::kth_light : + colors::bch_green; + + // Skip hint + Element skip_hint = (elapsed > 1000) ? + (text("Press any key to skip...") | color(colors::gray) | dim) : + text(""); + + return vbox({ + filler(), + hbox({ + filler(), + vbox(logo_elements), + filler(), + }), + text(""), + hbox({ + filler(), + slogan_element, + filler(), + }), + text(""), + text(""), + hbox({ + filler(), + skip_hint, + filler(), + }), + filler(), + }) | border | color(border_color); +} + +Element tui_dashboard::render_dashboard() { + return vbox({ + render_header_bar(), + separator() | color(colors::dark_gray), + hbox({ + vbox({ + render_blockchain_panel(), + render_sync_panel(), + }) | flex, + separator() | color(colors::dark_gray), + vbox({ + render_network_panel(), + render_mempool_panel(), + render_mining_panel(), + }) | flex, + }) | flex, + separator() | color(colors::dark_gray), + render_navigation_bar(), + render_footer(), + }) | border | color(colors::kth_purple); +} + +Element tui_dashboard::render_network_screen() { + return render_placeholder("NETWORK"); +} + +Element tui_dashboard::render_blockchain_screen() { + return render_placeholder("BLOCKCHAIN"); +} + +Element tui_dashboard::render_mempool_screen() { + return render_placeholder("MEMPOOL"); +} + +Element tui_dashboard::render_logs_screen() { + return render_placeholder("LOGS"); +} + +Element tui_dashboard::render_terminal_screen() { + // C64 color scheme + auto const c64_blue = Color::RGB(64, 50, 133); // C64 blue background + auto const c64_light_blue = Color::RGB(134, 122, 222); // C64 light blue text + + // Calculate how many lines we can show + size_t const visible_lines = 20; + + // Get the lines to display (last N lines from history) + Elements lines; + size_t start_idx = terminal_history_.size() > visible_lines ? + terminal_history_.size() - visible_lines : 0; + + for (size_t i = start_idx; i < terminal_history_.size(); ++i) { + lines.push_back(text(terminal_history_[i]) | color(c64_light_blue)); + } + + // Current input line with blinking cursor + auto now = std::chrono::steady_clock::now(); + auto ms = std::chrono::duration_cast(now.time_since_epoch()).count(); + bool cursor_visible = (ms / 500) % 2 == 0; + + std::string input_line = terminal_input_; + if (cursor_visible) { + input_line += "\u2588"; // Block cursor + } else { + input_line += " "; + } + lines.push_back(text(input_line) | color(c64_light_blue)); + + // Fill remaining space + while (lines.size() < visible_lines + 1) { + lines.insert(lines.begin(), text("")); + } + + return vbox({ + // C64 style header + hbox({ + filler(), + text(" **** KNUTH 64 BASIC V2 **** ") | bold | color(c64_light_blue), + filler(), + }) | bgcolor(c64_blue), + text("") | bgcolor(c64_blue), + // Terminal content + vbox(lines) | flex | bgcolor(c64_blue), + text("") | bgcolor(c64_blue), + separator() | color(colors::dark_gray), + render_navigation_bar(), + hbox({ + filler(), + text("Type commands. Press ") | color(colors::gray), + text("ESC") | bold | color(colors::bch_green), + text(" to show exit dialog.") | color(colors::gray), + filler(), + }) | size(HEIGHT, EQUAL, 1), + }) | border | color(c64_blue); +} + +Element tui_dashboard::render_placeholder(std::string const& title) { + return vbox({ + render_header_bar(), + separator() | color(colors::dark_gray), + filler(), + hbox({ + filler(), + vbox({ + text("┌─────────────────────────────┐") | color(colors::kth_violet), + text("│ │") | color(colors::kth_violet), + text("│ " + title + " SCREEN ") | color(colors::kth_light) | bold, + text("│ │") | color(colors::kth_violet), + text("│ Coming soon... │") | color(colors::gray), + text("│ │") | color(colors::kth_violet), + text("└─────────────────────────────┘") | color(colors::kth_violet), + }), + filler(), + }), + filler(), + separator() | color(colors::dark_gray), + render_navigation_bar(), + render_footer(), + }) | border | color(colors::kth_purple); +} + +Element tui_dashboard::render_header_bar() { + auto uptime = std::chrono::duration_cast( + std::chrono::system_clock::now() - status_.start_time); + + auto state_str = state_to_string(status_.state); + auto state_col = state_color(status_.state); + + std::string status_icon; + switch (status_.state) { + case node_status::sync_state::synced: status_icon = "● "; break; + case node_status::sync_state::error: status_icon = "✖ "; break; + case node_status::sync_state::starting: + case node_status::sync_state::connecting: status_icon = "◐ "; break; + default: status_icon = "◉ "; break; + } + + return hbox({ + text(" Knuth ") | bold | color(colors::kth_violet), + text("v" + status_.version) | color(colors::gray) | dim, + text(" "), + separator() | color(colors::dark_gray), + text(" "), + text(status_icon) | color(state_col) | bold, + text(state_str) | color(state_col) | bold, + filler(), + text("⛓ ") | color(colors::cyan), + text(status_.network_name) | color(colors::cyan) | bold, + text(" "), + separator() | color(colors::dark_gray), + text(" "), + text("Height: ") | color(colors::gray), + text(format_number(status_.chain_height)) | color(colors::white) | bold, + text(" "), + separator() | color(colors::dark_gray), + text(" "), + text("⏱ ") | color(colors::gray), + text(format_duration(uptime)) | color(colors::white), + text(" "), + }) | size(HEIGHT, EQUAL, 1); +} + +Element tui_dashboard::render_navigation_bar() { + Elements tabs; + + for (auto const& scr : navigable_screens_) { + bool is_current = (scr == current_screen_); + auto name = screen_name(scr); + + if (is_current) { + tabs.push_back(text(" " + name + " ") | bold | color(colors::kth_purple) | inverted); + } else { + tabs.push_back(text(" " + name + " ") | color(colors::gray)); + } + tabs.push_back(text(" ")); + } + + return hbox({ + text(" ◀ ") | color(colors::kth_light), + hbox(tabs), + text(" ▶ ") | color(colors::kth_light), + filler(), + text("← → navigate") | color(colors::dark_gray) | dim, + text(" "), + }) | size(HEIGHT, EQUAL, 1); +} + +Element tui_dashboard::render_blockchain_panel() { + Elements rows; + + rows.push_back(hbox({ + text("█ ") | color(colors::bch_green), + text("BLOCK HEIGHT") | bold | color(colors::bch_green), + })); + + rows.push_back(hbox({ + text(" "), + text(format_number(status_.chain_height)) | bold | color(colors::white) | size(WIDTH, GREATER_THAN, 10), + status_.target_height > 0 ? + text(" / " + format_number(status_.target_height)) | color(colors::gray) : + text(""), + })); + + rows.push_back(text("")); + + if (!status_.best_block_hash.empty()) { + rows.push_back(hbox({ + text(" Hash: ") | color(colors::gray), + text(truncate_hash(status_.best_block_hash, 24) + "...") | color(colors::cyan), + })); + } + + if (status_.difficulty > 0) { + rows.push_back(hbox({ + text(" Difficulty: ") | color(colors::gray), + text(format_difficulty(status_.difficulty)) | color(colors::orange), + })); + } + + if (status_.last_block_time != std::chrono::system_clock::time_point{}) { + rows.push_back(hbox({ + text(" Last block: ") | color(colors::gray), + text(format_time_ago(status_.last_block_time)) | color(colors::white), + })); + } + + return window(text(" ⛏ BLOCKCHAIN ") | bold | color(colors::bch_green), vbox(rows) | flex) | flex; +} + +Element tui_dashboard::render_sync_panel() { + Elements rows; + + if (status_.headers_total > 0) { + float progress = static_cast(status_.headers_synced) / + static_cast(status_.headers_total); + progress = std::clamp(progress, 0.0f, 1.0f); + int pct = static_cast(progress * 100); + bool done = status_.headers_synced >= status_.headers_total; + + rows.push_back(hbox({ + text("Headers: ") | color(colors::gray), + text(format_number(status_.headers_synced)) | color(done ? colors::green : colors::blue), + text(" / ") | color(colors::dark_gray), + text(format_number(status_.headers_total)) | color(colors::gray), + text(" "), + text(std::to_string(pct) + "%") | color(done ? colors::green : colors::blue), + done ? text(" ✓") | color(colors::green) : text(""), + })); + + rows.push_back(hbox({ + gauge(progress) | flex | color(done ? colors::green : colors::blue), + })); + + if (!done && status_.headers_per_second > 0) { + rows.push_back(hbox({ + text(" ") | color(colors::gray), + text("↓ " + format_number(status_.headers_per_second) + "/s") | color(colors::cyan), + })); + } + + rows.push_back(text("")); + } + + if (status_.blocks_total > 0) { + float progress = static_cast(status_.blocks_synced) / + static_cast(status_.blocks_total); + progress = std::clamp(progress, 0.0f, 1.0f); + int pct = static_cast(progress * 100); + bool done = status_.blocks_synced >= status_.blocks_total; + + rows.push_back(hbox({ + text("Blocks: ") | color(colors::gray), + text(format_number(status_.blocks_synced)) | color(done ? colors::green : colors::orange), + text(" / ") | color(colors::dark_gray), + text(format_number(status_.blocks_total)) | color(colors::gray), + text(" "), + text(std::to_string(pct) + "%") | color(done ? colors::green : colors::orange), + done ? text(" ✓") | color(colors::green) : text(""), + })); + + rows.push_back(hbox({ + gauge(progress) | flex | color(done ? colors::green : colors::orange), + })); + + if (!done) { + Elements speed_row; + speed_row.push_back(text(" ") | color(colors::gray)); + if (status_.blocks_per_second > 0) { + speed_row.push_back(text("↓ " + format_number(status_.blocks_per_second) + "/s") | color(colors::cyan)); + } + if (status_.blocks_eta.count() > 0) { + speed_row.push_back(text(" ETA: ") | color(colors::gray)); + speed_row.push_back(text(format_duration(status_.blocks_eta)) | color(colors::white)); + } + if (!speed_row.empty()) { + rows.push_back(hbox(speed_row)); + } + } + } + + if (rows.empty()) { + rows.push_back(text("Waiting for sync data...") | color(colors::gray) | dim); + } + + return window(text(" ⟳ SYNCHRONIZATION ") | bold | color(colors::kth_violet), vbox(rows) | flex) | flex; +} + +Element tui_dashboard::render_network_panel() { + size_t total_peers = status_.peers_inbound + status_.peers_outbound; + + Elements rows; + + rows.push_back(hbox({ + text("⬡ ") | color(total_peers > 0 ? colors::green : colors::red), + text("Peers: ") | color(colors::gray), + text(std::to_string(total_peers)) | bold | color(total_peers > 0 ? colors::green : colors::red), + text(" (") | color(colors::dark_gray), + text("↑" + std::to_string(status_.peers_outbound)) | color(colors::cyan), + text(" ↓" + std::to_string(status_.peers_inbound)) | color(colors::kth_violet), + text(")") | color(colors::dark_gray), + })); + + rows.push_back(text("")); + + rows.push_back(hbox({ + text("↓ ") | color(colors::green) | bold, + text(format_bytes_speed(status_.bytes_received)) | color(colors::green), + text(" "), + text("↑ ") | color(colors::blue) | bold, + text(format_bytes_speed(status_.bytes_sent)) | color(colors::blue), + })); + + if (status_.total_bytes_received > 0 || status_.total_bytes_sent > 0) { + rows.push_back(hbox({ + text("Total: ") | color(colors::gray), + text("↓" + format_bytes(status_.total_bytes_received)) | color(colors::green) | dim, + text(" ↑" + format_bytes(status_.total_bytes_sent)) | color(colors::blue) | dim, + })); + } + + if (status_.avg_ping_ms > 0) { + rows.push_back(hbox({ + text("Ping: ") | color(colors::gray), + text(std::to_string(status_.avg_ping_ms) + "ms") | color( + status_.avg_ping_ms < 100 ? colors::green : + status_.avg_ping_ms < 500 ? colors::orange : colors::red), + })); + } + + return window(text(" ⚡ NETWORK ") | bold | color(colors::cyan), vbox(rows) | flex) | flex; +} + +Element tui_dashboard::render_mempool_panel() { + Elements rows; + + rows.push_back(hbox({ + text("Transactions: ") | color(colors::gray), + text(format_number(status_.mempool_tx_count)) | bold | color(colors::kth_violet), + })); + + rows.push_back(hbox({ + text("Size: ") | color(colors::gray), + text(format_bytes(status_.mempool_size_bytes)) | color(colors::white), + })); + + if (status_.mempool_avg_fee > 0) { + rows.push_back(hbox({ + text("Avg fee: ") | color(colors::gray), + text(std::to_string(static_cast(status_.mempool_avg_fee)) + " sat/B") | color(colors::orange), + })); + } + + if (status_.mempool_min_fee > 0) { + rows.push_back(hbox({ + text("Min fee: ") | color(colors::gray), + text(std::to_string(static_cast(status_.mempool_min_fee)) + " sat/B") | color(colors::green), + })); + } + + return window(text(" 📦 MEMPOOL ") | bold | color(colors::kth_violet), vbox(rows) | flex) | flex; +} + +Element tui_dashboard::render_mining_panel() { + Elements rows; + + if (status_.network_hashrate > 0) { + rows.push_back(hbox({ + text("Network Hashrate: ") | color(colors::gray), + text(format_hashrate(status_.network_hashrate)) | bold | color(colors::bch_green), + })); + } + + if (status_.blocks_until_retarget > 0) { + rows.push_back(hbox({ + text("Next retarget: ") | color(colors::gray), + text(format_number(status_.blocks_until_retarget) + " blocks") | color(colors::orange), + })); + } + + if (status_.blocks_until_halving > 0) { + rows.push_back(hbox({ + text("Next halving: ") | color(colors::gray), + text(format_number(status_.blocks_until_halving) + " blocks") | color(colors::bch_green), + })); + } + + if (rows.empty()) { + rows.push_back(text("Mining data pending...") | color(colors::gray) | dim); + } + + return window(text(" ⛏ MINING ") | bold | color(colors::bch_green), vbox(rows) | flex) | flex; +} + +Element tui_dashboard::render_footer() { + return hbox({ + filler(), + text("Press ") | color(colors::gray), + text("Q") | bold | color(colors::bch_green), + text(" or ") | color(colors::gray), + text("ESC") | bold | color(colors::bch_green), + text(" to exit") | color(colors::gray), + text(" │ ") | color(colors::dark_gray), + text("kth.cash") | color(colors::kth_violet) | bold, + filler(), + }) | size(HEIGHT, EQUAL, 1); +} + +// Helper implementations + +std::string tui_dashboard::format_bytes(size_t bytes) const { + if (bytes >= 1024ULL * 1024 * 1024 * 1024) { + return std::format("{:.2f} TB", bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)); + } + if (bytes >= 1024ULL * 1024 * 1024) { + return std::format("{:.2f} GB", bytes / (1024.0 * 1024.0 * 1024.0)); + } + if (bytes >= 1024 * 1024) { + return std::format("{:.1f} MB", bytes / (1024.0 * 1024.0)); + } + if (bytes >= 1024) { + return std::format("{:.1f} KB", bytes / 1024.0); + } + return std::format("{} B", bytes); +} + +std::string tui_dashboard::format_bytes_speed(size_t bytes_per_sec) const { + return format_bytes(bytes_per_sec) + "/s"; +} + +std::string tui_dashboard::format_duration(std::chrono::seconds secs) const { + auto total = secs.count(); + auto days = total / 86400; + auto hours = (total % 86400) / 3600; + auto minutes = (total % 3600) / 60; + auto seconds = total % 60; + + return std::format("{:03}d {:02}h {:02}m {:02}s", days, hours, minutes, seconds); +} + +std::string tui_dashboard::format_time_ago(std::chrono::system_clock::time_point tp) const { + auto now = std::chrono::system_clock::now(); + auto diff = std::chrono::duration_cast(now - tp); + return format_duration(diff) + " ago"; +} + +std::string tui_dashboard::format_hashrate(double hashrate) const { + if (hashrate >= 1e18) { + return std::format("{:.2f} EH/s", hashrate / 1e18); + } + if (hashrate >= 1e15) { + return std::format("{:.2f} PH/s", hashrate / 1e15); + } + if (hashrate >= 1e12) { + return std::format("{:.2f} TH/s", hashrate / 1e12); + } + if (hashrate >= 1e9) { + return std::format("{:.2f} GH/s", hashrate / 1e9); + } + if (hashrate >= 1e6) { + return std::format("{:.2f} MH/s", hashrate / 1e6); + } + return std::format("{:.0f} H/s", hashrate); +} + +std::string tui_dashboard::format_difficulty(double diff) const { + if (diff >= 1e15) { + return std::format("{:.2f}P", diff / 1e15); + } + if (diff >= 1e12) { + return std::format("{:.2f}T", diff / 1e12); + } + if (diff >= 1e9) { + return std::format("{:.2f}G", diff / 1e9); + } + if (diff >= 1e6) { + return std::format("{:.2f}M", diff / 1e6); + } + if (diff >= 1e3) { + return std::format("{:.2f}K", diff / 1e3); + } + return std::format("{:.2f}", diff); +} + +std::string tui_dashboard::format_number(size_t num) const { + auto s = std::to_string(num); + std::string result; + result.reserve(s.size() + s.size() / 3); + int count = 0; + for (auto it = s.rbegin(); it != s.rend(); ++it) { + if (count > 0 && count % 3 == 0) { + result.insert(result.begin(), ','); + } + result.insert(result.begin(), *it); + ++count; + } + return result; +} + +std::string tui_dashboard::state_to_string(node_status::sync_state state) const { + switch (state) { + case node_status::sync_state::starting: return "STARTING"; + case node_status::sync_state::connecting: return "CONNECTING"; + case node_status::sync_state::syncing_headers: return "SYNCING HEADERS"; + case node_status::sync_state::syncing_blocks: return "SYNCING BLOCKS"; + case node_status::sync_state::synced: return "SYNCED"; + case node_status::sync_state::error: return "ERROR"; + default: return "UNKNOWN"; + } +} + +Color tui_dashboard::state_color(node_status::sync_state state) const { + switch (state) { + case node_status::sync_state::synced: return colors::bch_green; + case node_status::sync_state::error: return colors::red; + case node_status::sync_state::syncing_headers: + case node_status::sync_state::syncing_blocks: return colors::kth_violet; + case node_status::sync_state::connecting: return colors::cyan; + default: return colors::gray; + } +} + +std::string tui_dashboard::truncate_hash(std::string const& hash, size_t len) const { + if (hash.length() <= len) return hash; + return hash.substr(0, len); +} + +std::string tui_dashboard::screen_name(screen_id id) const { + switch (id) { + case screen_id::splash: return "SPLASH"; + case screen_id::dashboard: return "DASHBOARD"; + case screen_id::network: return "NETWORK"; + case screen_id::blockchain: return "BLOCKCHAIN"; + case screen_id::mempool: return "MEMPOOL"; + case screen_id::logs: return "LOGS"; + case screen_id::terminal: return "TERMINAL"; + default: return "UNKNOWN"; + } +} + +void tui_dashboard::terminal_add_output(std::string const& line) { + terminal_history_.push_back(line); + // Limit history size + while (terminal_history_.size() > terminal_history_max_) { + terminal_history_.erase(terminal_history_.begin()); + } +} + +void tui_dashboard::terminal_process_command() { + // Add command to history + terminal_add_output(terminal_input_); + + // Parse and execute command + std::string cmd = terminal_input_; + terminal_input_.clear(); + + // Convert to uppercase for comparison + std::string cmd_upper; + for (char c : cmd) { + cmd_upper += (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c; + } + + // Simple command processing + if (cmd_upper.empty()) { + // Empty command, just show READY + } else if (cmd_upper == "HELP" || cmd_upper == "?") { + terminal_add_output(""); + terminal_add_output("AVAILABLE COMMANDS:"); + terminal_add_output(" HELP - SHOW THIS HELP"); + terminal_add_output(" STATUS - SHOW NODE STATUS"); + terminal_add_output(" PEERS - SHOW PEER COUNT"); + terminal_add_output(" HEIGHT - SHOW BLOCK HEIGHT"); + terminal_add_output(" VERSION - SHOW VERSION"); + terminal_add_output(" CLEAR - CLEAR SCREEN"); + terminal_add_output(" SYS - SHOW SYSTEM INFO"); + terminal_add_output(""); + } else if (cmd_upper == "STATUS") { + terminal_add_output(""); + terminal_add_output("NODE STATUS: " + state_to_string(status_.state)); + terminal_add_output(""); + } else if (cmd_upper == "PEERS") { + terminal_add_output(""); + terminal_add_output(std::format("PEERS: {} OUTBOUND, {} INBOUND", + status_.peers_outbound, status_.peers_inbound)); + terminal_add_output(""); + } else if (cmd_upper == "HEIGHT") { + terminal_add_output(""); + terminal_add_output(std::format("BLOCK HEIGHT: {}", status_.chain_height)); + terminal_add_output(""); + } else if (cmd_upper == "VERSION") { + terminal_add_output(""); + terminal_add_output("KNUTH NODE V" + status_.version); + terminal_add_output(""); + } else if (cmd_upper == "CLEAR" || cmd_upper == "CLS") { + terminal_history_.clear(); + terminal_history_.push_back(""); + terminal_history_.push_back(" **** KNUTH 64 BASIC V2 ****"); + terminal_history_.push_back(""); + terminal_history_.push_back(" 64K RAM SYSTEM 38911 BASIC BYTES FREE"); + terminal_history_.push_back(""); + } else if (cmd_upper == "SYS") { + terminal_add_output(""); + terminal_add_output(std::format("MEMORY: {} BYTES", status_.memory_usage)); + terminal_add_output(std::format("CPU: {:.1f}%", status_.cpu_usage)); + terminal_add_output(std::format("DB CACHE: {} BYTES", status_.db_cache_size)); + terminal_add_output(""); + } else if (cmd_upper.substr(0, 4) == "LOAD" || cmd_upper.substr(0, 3) == "RUN" || + cmd_upper.substr(0, 4) == "LIST" || cmd_upper.substr(0, 4) == "POKE" || + cmd_upper.substr(0, 4) == "PEEK") { + terminal_add_output(""); + terminal_add_output("?SYNTAX ERROR"); + terminal_add_output(" (JUST KIDDING, THIS IS NOT A REAL C64)"); + terminal_add_output(""); + } else { + terminal_add_output(""); + terminal_add_output("?SYNTAX ERROR"); + terminal_add_output(""); + } + + terminal_add_output("READY."); +} + +tui_dashboard::ptr make_tui_dashboard() { + return std::make_unique(); +} + +} // namespace kth::node_exe diff --git a/src/node-exe/src/tui_dashboard.hpp b/src/node-exe/src/tui_dashboard.hpp new file mode 100644 index 00000000..b6edbb76 --- /dev/null +++ b/src/node-exe/src/tui_dashboard.hpp @@ -0,0 +1,195 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_EXE_TUI_DASHBOARD_HPP +#define KTH_NODE_EXE_TUI_DASHBOARD_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace kth::node_exe { + +/// Available screens in the TUI +enum class screen_id { + splash, // Intro animation screen + dashboard, // Main dashboard with node stats + network, // Network details (placeholder) + blockchain, // Blockchain details (placeholder) + mempool, // Mempool details (placeholder) + logs, // Log viewer (placeholder) + terminal, // C64-style terminal +}; + +/// Node status for TUI display - Mining focused +struct node_status { + // Version & Network + std::string version; + std::string network_name{"BCH Mainnet"}; + std::chrono::system_clock::time_point start_time; + + // Sync status + enum class sync_state { starting, connecting, syncing_headers, syncing_blocks, synced, error }; + sync_state state{sync_state::starting}; + std::string error_message; + + // Blockchain info + size_t chain_height{0}; + size_t target_height{0}; + std::string best_block_hash; + double difficulty{0.0}; + std::chrono::system_clock::time_point last_block_time; + + // Headers sync + size_t headers_synced{0}; + size_t headers_total{0}; + size_t headers_per_second{0}; + + // Blocks sync + size_t blocks_synced{0}; + size_t blocks_total{0}; + size_t blocks_per_second{0}; + std::chrono::seconds blocks_eta{0}; + + // Network + size_t peers_outbound{0}; + size_t peers_inbound{0}; + size_t peers_max_outbound{8}; + size_t bytes_received{0}; // bytes per second + size_t bytes_sent{0}; // bytes per second + size_t total_bytes_received{0}; // total bytes + size_t total_bytes_sent{0}; // total bytes + size_t avg_ping_ms{0}; + + // Mempool + size_t mempool_tx_count{0}; + size_t mempool_size_bytes{0}; + double mempool_min_fee{0.0}; // sat/byte + double mempool_avg_fee{0.0}; // sat/byte + + // Mining info + double network_hashrate{0.0}; // EH/s + size_t blocks_until_retarget{0}; + size_t blocks_until_halving{0}; + + // Performance + size_t db_cache_size{0}; + double cpu_usage{0.0}; + size_t memory_usage{0}; +}; + +/// TUI Dashboard using FTXUI - Multi-screen with animations +class tui_dashboard { +public: + using ptr = std::unique_ptr; + + tui_dashboard(); + ~tui_dashboard(); + + /// Start the TUI in a background thread + void start(); + + /// Stop the TUI + void stop(); + + /// Update node status (thread-safe) + void update_status(node_status const& status); + + /// Check if TUI is running + bool is_running() const; + + /// Request exit (e.g., from signal handler) + void request_exit(); + +private: + // Main render dispatcher + ftxui::Element render(); + + // Screen renderers + ftxui::Element render_splash(); + ftxui::Element render_dashboard(); + ftxui::Element render_network_screen(); + ftxui::Element render_blockchain_screen(); + ftxui::Element render_mempool_screen(); + ftxui::Element render_logs_screen(); + ftxui::Element render_terminal_screen(); + ftxui::Element render_placeholder(std::string const& title); + + // Terminal helpers + void terminal_process_command(); + void terminal_add_output(std::string const& text); + + // Dashboard panels + ftxui::Element render_header_bar(); + ftxui::Element render_blockchain_panel(); + ftxui::Element render_sync_panel(); + ftxui::Element render_network_panel(); + ftxui::Element render_mempool_panel(); + ftxui::Element render_mining_panel(); + ftxui::Element render_footer(); + ftxui::Element render_navigation_bar(); + + // Helpers + std::string format_bytes(size_t bytes) const; + std::string format_bytes_speed(size_t bytes_per_sec) const; + std::string format_duration(std::chrono::seconds secs) const; + std::string format_time_ago(std::chrono::system_clock::time_point tp) const; + std::string format_hashrate(double hashrate) const; + std::string format_difficulty(double diff) const; + std::string format_number(size_t num) const; + std::string state_to_string(node_status::sync_state state) const; + ftxui::Color state_color(node_status::sync_state state) const; + std::string truncate_hash(std::string const& hash, size_t len = 16) const; + std::string screen_name(screen_id id) const; + + // Navigation + void next_screen(); + void prev_screen(); + + std::atomic running_{false}; + std::atomic exit_requested_{false}; + std::thread ui_thread_; + + // Screen management + screen_id current_screen_{screen_id::splash}; + std::vector navigable_screens_; + + // Splash animation state + std::chrono::steady_clock::time_point splash_start_; + int animation_frame_{0}; + bool splash_complete_{false}; + + // Exit confirmation state + bool show_exit_confirm_{false}; + bool show_goodbye_{false}; + std::chrono::steady_clock::time_point goodbye_start_; + + // Terminal state (C64 style) + std::string terminal_input_; + std::vector terminal_history_; + size_t terminal_history_max_{100}; + + // Protected by mutex for thread-safe access + mutable std::mutex status_mutex_; + node_status status_; + std::atomic screen_{nullptr}; +}; + +/// Create a TUI dashboard +[[nodiscard]] +tui_dashboard::ptr make_tui_dashboard(); + +} // namespace kth::node_exe + +#endif // KTH_NODE_EXE_TUI_DASHBOARD_HPP diff --git a/src/node-exe/src/tui_dashboard_v1.cpp b/src/node-exe/src/tui_dashboard_v1.cpp new file mode 100644 index 00000000..aa7332c3 --- /dev/null +++ b/src/node-exe/src/tui_dashboard_v1.cpp @@ -0,0 +1,299 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "tui_dashboard.hpp" + +#include +#include +#include + +namespace kth::node_exe { + +using namespace ftxui; + +tui_dashboard::tui_dashboard() { + status_.start_time = std::chrono::system_clock::now(); +} + +tui_dashboard::~tui_dashboard() { + stop(); +} + +void tui_dashboard::start() { + if (running_.exchange(true)) { + return; // Already running + } + + ui_thread_ = std::thread([this] { + auto screen = ScreenInteractive::Fullscreen(); + screen_.store(&screen); + + auto renderer = Renderer([this] { + return render(); + }); + + // Refresh every 500ms + std::atomic refresh_ui_continue{true}; + std::thread refresh_ui([&] { + while (refresh_ui_continue && !exit_requested_) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + screen.PostEvent(Event::Custom); + } + }); + + // Handle exit request + auto component = CatchEvent(renderer, [&](Event event) { + if (exit_requested_) { + screen.Exit(); + return true; + } + if (event == Event::Character('q') || event == Event::Escape) { + exit_requested_ = true; + screen.Exit(); + return true; + } + return false; + }); + + screen.Loop(component); + + refresh_ui_continue = false; + if (refresh_ui.joinable()) { + refresh_ui.join(); + } + + screen_.store(nullptr); + running_ = false; + }); +} + +void tui_dashboard::stop() { + exit_requested_ = true; + if (ui_thread_.joinable()) { + ui_thread_.join(); + } +} + +void tui_dashboard::update_status(node_status const& status) { + { + std::lock_guard lock(status_mutex_); + status_ = status; + } + auto* scr = screen_.load(); + if (scr != nullptr) { + scr->PostEvent(Event::Custom); + } +} + +bool tui_dashboard::is_running() const { + return running_; +} + +void tui_dashboard::request_exit() { + exit_requested_ = true; + auto* scr = screen_.load(); + if (scr != nullptr) { + scr->PostEvent(Event::Custom); + } +} + +Element tui_dashboard::render() { + return vbox({ + render_header(), + separator(), + render_sync_panel(), + separator(), + render_network_panel(), + separator(), + render_mempool_panel(), + filler(), + separator(), + render_footer(), + }) | border; +} + +Element tui_dashboard::render_header() { + auto uptime = std::chrono::duration_cast( + std::chrono::system_clock::now() - status_.start_time); + + return hbox({ + text("Knuth") | bold, + text(" " + status_.version) | dim, + filler(), + text(status_.network_name) | color(Color::Cyan), + text(" "), + text("Height: ") | dim, + text(std::to_string(status_.chain_height)) | bold, + text(" "), + text("Uptime: ") | dim, + text(format_duration(uptime)), + }) | hcenter; +} + +Element tui_dashboard::render_sync_panel() { + Elements content; + + auto state_str = state_to_string(status_.state); + auto state_color = Color::Yellow; + if (status_.state == node_status::sync_state::synced) { + state_color = Color::Green; + } else if (status_.state == node_status::sync_state::error) { + state_color = Color::Red; + } + + content.push_back(hbox({ + text("Status: ") | dim, + text(state_str) | bold | color(state_color), + })); + + // Headers progress + if (status_.headers_total > 0) { + float headers_progress = static_cast(status_.headers_synced) / + static_cast(status_.headers_total); + headers_progress = std::clamp(headers_progress, 0.0f, 1.0f); + + auto headers_pct = static_cast(headers_progress * 100); + bool headers_done = status_.headers_synced >= status_.headers_total; + + content.push_back(hbox({ + text("Headers: ") | dim, + text(std::to_string(status_.headers_synced) + "/" + + std::to_string(status_.headers_total)), + text(" "), + gauge(headers_progress) | flex | color(headers_done ? Color::Green : Color::Blue), + text(" " + std::to_string(headers_pct) + "%"), + headers_done ? text(" ✓") | color(Color::Green) : text(""), + })); + + if (!headers_done && status_.headers_per_second > 0) { + content.push_back(hbox({ + text(" ") | dim, + text(std::to_string(status_.headers_per_second) + " headers/s") | dim, + })); + } + } + + // Blocks progress + if (status_.blocks_total > 0) { + float blocks_progress = static_cast(status_.blocks_synced) / + static_cast(status_.blocks_total); + blocks_progress = std::clamp(blocks_progress, 0.0f, 1.0f); + + auto blocks_pct = static_cast(blocks_progress * 100); + bool blocks_done = status_.blocks_synced >= status_.blocks_total; + + content.push_back(hbox({ + text("Blocks: ") | dim, + text(std::to_string(status_.blocks_synced) + "/" + + std::to_string(status_.blocks_total)), + text(" "), + gauge(blocks_progress) | flex | color(blocks_done ? Color::Green : Color::Yellow), + text(" " + std::to_string(blocks_pct) + "%"), + blocks_done ? text(" ✓") | color(Color::Green) : text(""), + })); + + if (!blocks_done && status_.blocks_per_second > 0) { + auto eta_str = status_.blocks_eta.count() > 0 + ? format_duration(status_.blocks_eta) + : "calculating..."; + content.push_back(hbox({ + text(" ") | dim, + text(std::to_string(status_.blocks_per_second) + " blocks/s") | dim, + text(" ETA: ") | dim, + text(eta_str) | dim, + })); + } + } + + return window(text(" Sync "), vbox(content)); +} + +Element tui_dashboard::render_network_panel() { + auto peers_str = std::to_string(status_.peers_outbound) + "/" + + std::to_string(status_.peers_max_outbound) + " outbound"; + if (status_.peers_inbound > 0) { + peers_str += ", " + std::to_string(status_.peers_inbound) + " inbound"; + } + + return window(text(" Network "), vbox({ + hbox({ + text("Peers: ") | dim, + text(peers_str), + }), + hbox({ + text("Traffic: ") | dim, + text("↓ " + format_bytes(status_.bytes_received) + "/s") | color(Color::Green), + text(" "), + text("↑ " + format_bytes(status_.bytes_sent) + "/s") | color(Color::Blue), + }), + })); +} + +Element tui_dashboard::render_mempool_panel() { + return window(text(" Mempool "), hbox({ + text("Transactions: ") | dim, + text(std::to_string(status_.mempool_tx_count)), + text(" "), + text("Size: ") | dim, + text(format_bytes(status_.mempool_size_bytes)), + })); +} + +Element tui_dashboard::render_footer() { + return hbox({ + text("Press ") | dim, + text("q") | bold, + text(" or ") | dim, + text("ESC") | bold, + text(" to exit") | dim, + }) | hcenter; +} + +std::string tui_dashboard::format_bytes(size_t bytes) const { + std::ostringstream oss; + if (bytes >= 1024 * 1024 * 1024) { + oss << std::fixed << std::setprecision(1) << (bytes / (1024.0 * 1024.0 * 1024.0)) << " GB"; + } else if (bytes >= 1024 * 1024) { + oss << std::fixed << std::setprecision(1) << (bytes / (1024.0 * 1024.0)) << " MB"; + } else if (bytes >= 1024) { + oss << std::fixed << std::setprecision(1) << (bytes / 1024.0) << " KB"; + } else { + oss << bytes << " B"; + } + return oss.str(); +} + +std::string tui_dashboard::format_duration(std::chrono::seconds secs) const { + auto total = secs.count(); + auto hours = total / 3600; + auto minutes = (total % 3600) / 60; + auto seconds = total % 60; + + std::ostringstream oss; + if (hours > 0) { + oss << hours << "h " << minutes << "m"; + } else if (minutes > 0) { + oss << minutes << "m " << seconds << "s"; + } else { + oss << seconds << "s"; + } + return oss.str(); +} + +std::string tui_dashboard::state_to_string(node_status::sync_state state) const { + switch (state) { + case node_status::sync_state::starting: return "Starting..."; + case node_status::sync_state::syncing_headers: return "Syncing Headers"; + case node_status::sync_state::syncing_blocks: return "Syncing Blocks"; + case node_status::sync_state::synced: return "Synced"; + case node_status::sync_state::error: return "Error"; + default: return "Unknown"; + } +} + +tui_dashboard::ptr make_tui_dashboard() { + return std::make_unique(); +} + +} // namespace kth::node_exe diff --git a/src/node-exe/src/tui_dashboard_v1.hpp b/src/node-exe/src/tui_dashboard_v1.hpp new file mode 100644 index 00000000..7d6d6b78 --- /dev/null +++ b/src/node-exe/src/tui_dashboard_v1.hpp @@ -0,0 +1,113 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_EXE_TUI_DASHBOARD_HPP +#define KTH_NODE_EXE_TUI_DASHBOARD_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace kth::node_exe { + +/// Node status for TUI display +struct node_status { + // Chain info + std::string network_name{"BCH Mainnet"}; + size_t chain_height{0}; + size_t target_height{0}; + + // Sync status + enum class sync_state { starting, syncing_headers, syncing_blocks, synced, error }; + sync_state state{sync_state::starting}; + + // Headers sync + size_t headers_synced{0}; + size_t headers_total{0}; + size_t headers_per_second{0}; + + // Blocks sync + size_t blocks_synced{0}; + size_t blocks_total{0}; + size_t blocks_per_second{0}; + std::chrono::seconds blocks_eta{0}; + + // Network + size_t peers_outbound{0}; + size_t peers_inbound{0}; + size_t peers_max_outbound{8}; + size_t bytes_received{0}; + size_t bytes_sent{0}; + + // Mempool + size_t mempool_tx_count{0}; + size_t mempool_size_bytes{0}; + + // System + std::string version; + std::chrono::system_clock::time_point start_time; +}; + +/// TUI Dashboard using FTXUI +/// Displays real-time node status in a terminal UI +class tui_dashboard { +public: + using ptr = std::unique_ptr; + + tui_dashboard(); + ~tui_dashboard(); + + /// Start the TUI in a background thread + void start(); + + /// Stop the TUI + void stop(); + + /// Update node status (thread-safe) + void update_status(node_status const& status); + + /// Check if TUI is running + bool is_running() const; + + /// Request exit (e.g., from signal handler) + void request_exit(); + +private: + ftxui::Element render(); + ftxui::Element render_header(); + ftxui::Element render_sync_panel(); + ftxui::Element render_network_panel(); + ftxui::Element render_mempool_panel(); + ftxui::Element render_footer(); + + std::string format_bytes(size_t bytes) const; + std::string format_duration(std::chrono::seconds secs) const; + std::string state_to_string(node_status::sync_state state) const; + + std::atomic running_{false}; + std::atomic exit_requested_{false}; + std::thread ui_thread_; + + // Protected by mutex for thread-safe access + mutable std::mutex status_mutex_; + node_status status_; + std::atomic screen_{nullptr}; +}; + +/// Create a TUI dashboard +[[nodiscard]] +tui_dashboard::ptr make_tui_dashboard(); + +} // namespace kth::node_exe + +#endif // KTH_NODE_EXE_TUI_DASHBOARD_HPP diff --git a/src/node/CMakeLists.txt b/src/node/CMakeLists.txt index c06d87a8..9e82fdc2 100644 --- a/src/node/CMakeLists.txt +++ b/src/node/CMakeLists.txt @@ -147,23 +147,9 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(kth_sources_just_legacy ${kth_sources_just_legacy} src/full_node.cpp + src/sync_session.cpp src/executor/executor.cpp - src/protocols/protocol_block_in.cpp - src/protocols/protocol_block_out.cpp - src/protocols/protocol_block_sync.cpp - src/protocols/protocol_double_spend_proof_in.cpp - src/protocols/protocol_double_spend_proof_out.cpp - src/protocols/protocol_header_sync.cpp - src/protocols/protocol_transaction_in.cpp - src/protocols/protocol_transaction_out.cpp - - src/sessions/session_block_sync.cpp - src/sessions/session_header_sync.cpp - src/sessions/session_inbound.cpp - src/sessions/session_manual.cpp - src/sessions/session_outbound.cpp - src/utility/reservation.cpp src/utility/reservations.cpp @@ -196,30 +182,10 @@ set(kth_headers include/kth/node/utility/reservations.hpp include/kth/node/settings.hpp include/kth/node/full_node.hpp + include/kth/node/sync_session.hpp include/kth/node/parser.hpp ) -if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - set(kth_headers - ${kth_headers} - include/kth/node/sessions/session_header_sync.hpp - include/kth/node/sessions/session_outbound.hpp - include/kth/node/sessions/session_inbound.hpp - include/kth/node/sessions/session_block_sync.hpp - include/kth/node/sessions/session_manual.hpp - include/kth/node/sessions/session.hpp - include/kth/node/protocols/protocol_block_sync.hpp - include/kth/node/protocols/protocol_header_sync.hpp - include/kth/node/protocols/protocol_block_in.hpp - include/kth/node/protocols/protocol_transaction_out.hpp - include/kth/node/protocols/protocol_double_spend_proof_out.hpp - include/kth/node/protocols/protocol_double_spend_proof_in.hpp - include/kth/node/protocols/protocol_transaction_in.hpp - include/kth/node/protocols/protocol_block_out.hpp - ) -endif() - - add_library(${PROJECT_NAME} ${MODE} ${kth_sources} ${kth_headers}) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX CXX_STANDARD 23 CXX_STANDARD_REQUIRED TRUE) diff --git a/src/node/conanfile.py b/src/node/conanfile.py deleted file mode 100644 index bd303b00..00000000 --- a/src/node/conanfile.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (c) 2016-2025 Knuth Project developers. -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -from conan import ConanFile -from conan.tools.build.cppstd import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.files import copy -from kthbuild import KnuthConanFileV2, option_on_off - -required_conan_version = ">=2.0" - -class KnuthNodeConan(KnuthConanFileV2): - name = "node" - license = "https://opensource.org/licenses/MIT" - url = "https://github.com/k-nuth/node" - description = "Crypto full node" - settings = "os", "compiler", "build_type", "arch" - package_type = "library" - - options = { - "shared": [True, False], - "fPIC": [True, False], - "tests": [True, False], - "currency": ['BCH', 'BTC', 'LTC'], - "verbose": [True, False], - "mempool": [True, False], - "db": ['dynamic'], - "db_readonly": [True, False], - "march_id": ["ANY"], - "march_strategy": ["download_if_possible", "optimized", "download_or_fail"], - "cxxflags": ["ANY"], - "cflags": ["ANY"], - "cmake_export_compile_commands": [True, False], - "statistics": [True, False], - } - - default_options = { - "shared": False, - "fPIC": True, - "tests": True, - "currency": "BCH", - "march_strategy": "download_if_possible", - "verbose": False, - "mempool": False, - "db": "dynamic", - "db_readonly": False, - "cmake_export_compile_commands": False, - "statistics": False, - } - - exports_sources = "src/*", "CMakeLists.txt", "ci_utils/cmake/*", "cmake/*", "knuthbuildinfo.cmake", "include/*", "test/*", "console/*" - - def _is_legacy_db(self): - return self.options.db == "legacy" or self.options.db == "legacy_full" - - def validate(self): - KnuthConanFileV2.validate(self) - if self.info.settings.compiler.cppstd: - check_min_cppstd(self, "23") - - def build_requirements(self): - if self.options.tests: - self.test_requires("catch2/3.11.0") - - def requirements(self): - self.requires("blockchain/0.51.0", transitive_headers=True, transitive_libs=True) - - if self.settings.os != "Emscripten": - self.requires("network/0.54.0", transitive_headers=True, transitive_libs=True) - - if self.options.statistics: - self.requires("tabulate/1.0@", transitive_headers=True, transitive_libs=True) - - - def config_options(self): - KnuthConanFileV2.config_options(self) - - def configure(self): - KnuthConanFileV2.configure(self) - - self.options["*"].mempool = self.options.mempool - - self.options["*"].db_readonly = self.options.db_readonly - self.output.info("Compiling with read-only DB: %s" % (self.options.db_readonly,)) - - self.output.info("Compiling for currency: %s" % (self.options.currency,)) - self.output.info("Compiling with mempool: %s" % (self.options.mempool,)) - - - def package_id(self): - KnuthConanFileV2.package_id(self) - - def layout(self): - cmake_layout(self) - - def generate(self): - tc = self.cmake_toolchain_basis() - # tc.variables["CMAKE_VERBOSE_MAKEFILE"] = True - # tc.variables["WITH_CONSOLE"] = option_on_off(self.with_console) - tc.variables["WITH_MEMPOOL"] = option_on_off(self.options.mempool) - tc.variables["DB_READONLY_MODE"] = option_on_off(self.options.db_readonly) - tc.variables["STATISTICS"] = option_on_off(self.options.statistics) - tc.variables["CONAN_DISABLE_CHECK_COMPILER"] = option_on_off(True) - tc.generate() - tc = CMakeDeps(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure() - if not self.options.cmake_export_compile_commands: - cmake.build() - if self.options.tests: - cmake.test() - - # def imports(self): - # self.copy("*.h", "", "include") - - def package(self): - cmake = CMake(self) - cmake.install() - # rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - # rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) - # rmdir(self, os.path.join(self.package_folder, "res")) - # rmdir(self, os.path.join(self.package_folder, "share")) - - def package_info(self): - self.cpp_info.includedirs = ['include'] - self.cpp_info.libs = ["node"] diff --git a/src/node/include/kth/node.hpp b/src/node/include/kth/node.hpp index 9a999726..8d1b8ea2 100644 --- a/src/node/include/kth/node.hpp +++ b/src/node/include/kth/node.hpp @@ -21,25 +21,10 @@ #include #include #include +#include +#include #include -#if ! defined(__EMSCRIPTEN__) -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#endif #include #include diff --git a/src/node/include/kth/node/executor/executor.hpp b/src/node/include/kth/node/executor/executor.hpp index d8e81abc..618fe4b0 100644 --- a/src/node/include/kth/node/executor/executor.hpp +++ b/src/node/include/kth/node/executor/executor.hpp @@ -5,6 +5,7 @@ #ifndef KTH_NODE_EXE_EXECUTOR_HPP_ #define KTH_NODE_EXE_EXECUTOR_HPP_ +#include #include #include #include @@ -16,10 +17,13 @@ #include #include +#include + namespace kth::node { struct executor { executor(kth::node::configuration const& config, bool stdout_enabled = true); + ~executor(); executor(executor const&) = delete; void operator=(executor const&) = delete; @@ -28,21 +32,25 @@ struct executor { bool do_initchain(std::string_view extra); #endif - // bool run(kth::handle0 handler); - #if ! defined(KTH_DB_READONLY) - bool init_run(std::string_view extra, start_modules mod, kth::handle0 handler); + /// Initialize and run the node, blocking until signal or error bool init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler); + + /// Initialize and run the node without blocking + bool init_run(std::string_view extra, start_modules mod, kth::handle0 handler); #endif + /// Signal the node to stop void signal_stop(); - // Close must be called from main thread. + /// Stop and cleanup the node (must be called from main thread) bool close(); + /// Access the full node kth::node::full_node& node(); kth::node::full_node const& node() const; + /// Check if node is stopped bool stopped() const; void print_version(std::string_view extra); @@ -54,7 +62,6 @@ struct executor { #endif bool verify_directory(); - bool run(); private: bool wait_for_signal_and_close(); @@ -66,9 +73,7 @@ struct executor { static void handle_stop(int code); - void handle_started(kth::code const& ec, start_modules mod); - void handle_running(kth::code const& ec); - void handle_stopped(kth::code const& ec); + void run_node_async(start_modules mod); // Termination state static std::promise stopping_; @@ -77,6 +82,11 @@ struct executor { kth::node::configuration config_; kth::node::full_node::ptr node_; kth::handle0 run_handler_; + + // IO context for running coroutines + ::asio::io_context io_context_; + std::thread io_thread_; + std::atomic running_{false}; }; // Localizable messages. diff --git a/src/node/include/kth/node/full_node.hpp b/src/node/include/kth/node/full_node.hpp index 63264a78..8b329a54 100644 --- a/src/node/include/kth/node/full_node.hpp +++ b/src/node/include/kth/node/full_node.hpp @@ -5,29 +5,44 @@ #ifndef KTH_NODE_FULL_NODE_HPP #define KTH_NODE_FULL_NODE_HPP +// ============================================================================= +// Full Node - Bitcoin Full Node Implementation +// ============================================================================= +// +// This class represents a complete Bitcoin full node that combines: +// - P2P networking (via network::p2p_node composition) [non-WASM only] +// - Blockchain storage and validation (via blockchain::block_chain) +// +// ARCHITECTURE: +// ------------- +// Uses composition instead of inheritance: +// full_node HAS-A p2p_node (networking) [non-WASM only] +// full_node HAS-A block_chain (blockchain) +// +// API: +// ---- +// All lifecycle methods use C++20 coroutines (asio::awaitable). +// This is a breaking change from the callback-based API in v0.x. +// +// WASM (Emscripten): +// ------------------ +// In WebAssembly builds, networking is disabled. Only blockchain +// operations are available. +// +// LEGACY FILES REPLACED: +// ---------------------- +// This new design eliminates the need for: +// - Inheritance from network::p2p +// - Virtual method overrides (attach_*_session) +// - node::session_inbound, session_outbound, session_manual +// +// ============================================================================= + #include #include -#if defined(KTH_STATISTICS_ENABLED) -#include -#include -// #include -#include -#include -// #include -#include -#include - -// #include - -//TODO(fernando): remove this workaround when Tabulate people fix their library. -namespace tabulate { -class Table; -} - -#endif - #include +#include #if ! defined(__EMSCRIPTEN__) #include #endif @@ -35,67 +50,25 @@ class Table; #include #include -#if ! defined(__EMSCRIPTEN__) -#include -#include -#endif - -#include +#include namespace kth::node { +/// Startup mode selection enum class start_modules { all, just_chain, just_p2p }; -#if defined(KTH_STATISTICS_ENABLED) - -//TODO(fernando): move to another place -struct stdev_sample { - template - auto operator()(T const& x) { - auto n = boost::accumulators::count(x); - return std::sqrt(boost::accumulators::variance(x) * (n / (n - 1.0))); - } -}; - -//TODO(fernando): move to another place -template -struct statistics_entry { - T1 transactions; - T1 inputs; - T1 outputs; - T1 wait_total_ms; - T1 validation_total_ms; - T1 validation_per_input_us; - T1 deserialization_per_input_us; - T1 check_per_input_us; - T1 population_per_input_us; - T1 accept_per_input_us; - T1 connect_per_input_us; - T1 deposit_per_input_us; - T2 cache_efficiency; // (hits/queries) -}; - -using accum_t = boost::accumulators::accumulator_set>; - -#endif - +// Helper to set cashaddr prefix based on network struct multi_crypto_setter { multi_crypto_setter() { set_cashaddr_prefix("bitcoincash"); } #if ! defined(__EMSCRIPTEN__) - multi_crypto_setter(network::settings const& net_settings) { + explicit multi_crypto_setter(network::settings const& net_settings) { #if defined(KTH_CURRENCY_BCH) switch (net_settings.identifier) { case netmagic::bch_mainnet: @@ -104,7 +77,6 @@ struct multi_crypto_setter { case netmagic::bch_testnet: case netmagic::bch_testnet4: case netmagic::bch_scalenet: - // case netmagic::bch_chipnet: // same net magic as bch_testnet4 set_cashaddr_prefix("bchtest"); break; case netmagic::bch_regtest: @@ -118,416 +90,144 @@ struct multi_crypto_setter { #endif }; -#if ! defined(__EMSCRIPTEN__) -#define OVERRIDE_COND override -#else -#define OVERRIDE_COND -#endif - - /// A full node on the Bitcoin P2P network. -class KND_API full_node - : public multi_crypto_setter -#if ! defined(__EMSCRIPTEN__) - , public network::p2p -#endif -{ +class KND_API full_node : public multi_crypto_setter { public: -#if defined(__EMSCRIPTEN__) - using result_handler = std::function; -#endif - using ptr = std::shared_ptr; - using reorganize_handler = blockchain::block_chain::reorganize_handler; - using transaction_handler = blockchain::block_chain::transaction_handler; - using ds_proof_handler = blockchain::block_chain::ds_proof_handler; /// Construct the full node. - full_node(configuration const& configuration); + explicit full_node(configuration const& configuration); - /// Ensure all threads are coalesced. - virtual ~full_node(); + /// Destructor - stops node if running. + ~full_node(); - // Start/Run sequences. - // ------------------------------------------------------------------------ + // Non-copyable, non-movable + full_node(full_node const&) = delete; + full_node& operator=(full_node const&) = delete; + full_node(full_node&&) = delete; + full_node& operator=(full_node&&) = delete; - /// Invoke startup and seeding sequence, call from constructing thread. - void start(result_handler handler) OVERRIDE_COND; + // Lifecycle + // ------------------------------------------------------------------------- - /// Invoke just chain startup, call from constructing thread. - void start_chain(result_handler handler); + /// Start the node (initialize chain and network). + [[nodiscard]] + ::asio::awaitable start(); - /// Synchronize the blockchain and then begin long running sessions, - /// call from start result handler. Call base method to skip sync. - void run(result_handler handler) OVERRIDE_COND; - void run_chain(result_handler handler) OVERRIDE_COND; + /// Run the node (start P2P connections and protocol handlers). + [[nodiscard]] + ::asio::awaitable run(); - // Shutdown. - // ------------------------------------------------------------------------ + /// Stop the node. + void stop(); - /// Idempotent call to signal work stop, start may be reinvoked after. - /// Returns the result of file save operation. - bool stop() OVERRIDE_COND; + /// Block until all work is complete. + void join(); - /// Blocking call to coalesce all work and then terminate all threads. - /// Call from thread that constructed this class, or don't call at all. - /// This calls stop, and start may be reinvoked after calling this. - bool close() OVERRIDE_COND; + /// Check if node is stopped. + [[nodiscard]] + bool stopped() const; - // Properties. - // ------------------------------------------------------------------------ + // Properties + // ------------------------------------------------------------------------- /// Node configuration settings. - virtual - const node::settings& node_settings() const; + [[nodiscard]] + node::settings const& node_settings() const; - /// Node configuration settings. - virtual + /// Blockchain configuration settings. + [[nodiscard]] blockchain::settings const& chain_settings() const; +#if ! defined(__EMSCRIPTEN__) + /// Network configuration settings. + [[nodiscard]] + kth::network::settings const& network_settings() const; +#endif + /// Blockchain query interface. - virtual - blockchain::safe_chain& chain(); + [[nodiscard]] + blockchain::block_chain& chain(); - /// Blockchain. - //TODO: remove this function and use safe_chain in the rpc lib - virtual + /// Blockchain (for mining and advanced use). + [[nodiscard]] blockchain::block_chain& chain_kth(); - // Subscriptions. - // ------------------------------------------------------------------------ - - /// Subscribe to blockchain reorganization and stop events. - virtual - void subscribe_blockchain(reorganize_handler&& handler); - - /// Subscribe to transaction pool acceptance and stop events. - virtual - void subscribe_transaction(transaction_handler&& handler); - - /// Subscribe to DSProof pool acceptance and stop events. - virtual - void subscribe_ds_proof(ds_proof_handler&& handler); - - // Init node utils. - // ------------------------------------------------------------------------ - static - domain::chain::block get_genesis_block(domain::config::network network); - - - -#if defined(KTH_STATISTICS_ENABLED) - void reset_current1_stats() { - stats_current1_accum_transactions_ = {}; - stats_current1_accum_inputs_ = {}; - stats_current1_accum_outputs_ = {}; - stats_current1_accum_wait_total_ms_ = {}; - stats_current1_accum_validation_total_ms_ = {}; - stats_current1_accum_validation_per_input_us_ = {}; - stats_current1_accum_deserialization_per_input_us_ = {}; - stats_current1_accum_check_per_input_us_ = {}; - stats_current1_accum_population_per_input_us_ = {}; - stats_current1_accum_accept_per_input_us_ = {}; - stats_current1_accum_connect_per_input_us_ = {}; - stats_current1_accum_deposit_per_input_us_ = {}; - stats_current1_accum_cache_efficiency_ = {}; - } - - void reset_current2_stats() { - stats_current2_accum_transactions_ = {}; - stats_current2_accum_inputs_ = {}; - stats_current2_accum_outputs_ = {}; - stats_current2_accum_wait_total_ms_ = {}; - stats_current2_accum_validation_total_ms_ = {}; - stats_current2_accum_validation_per_input_us_ = {}; - stats_current2_accum_deserialization_per_input_us_ = {}; - stats_current2_accum_check_per_input_us_ = {}; - stats_current2_accum_population_per_input_us_ = {}; - stats_current2_accum_accept_per_input_us_ = {}; - stats_current2_accum_connect_per_input_us_ = {}; - stats_current2_accum_deposit_per_input_us_ = {}; - stats_current2_accum_cache_efficiency_ = {}; - } - - void update_accum(size_t height, statistics_entry const& entry) { - if (height % accum_blocks_1_ == 0) { - reset_current1_stats(); - } - if (height % accum_blocks_2_ == 0) { - reset_current2_stats(); - } - - stats_current1_accum_transactions_(entry.transactions); - stats_current1_accum_inputs_(entry.inputs); - stats_current1_accum_outputs_(entry.outputs); - stats_current1_accum_wait_total_ms_(entry.wait_total_ms); - stats_current1_accum_validation_total_ms_(entry.validation_total_ms); - stats_current1_accum_validation_per_input_us_(entry.validation_per_input_us); - stats_current1_accum_deserialization_per_input_us_(entry.deserialization_per_input_us); - stats_current1_accum_check_per_input_us_(entry.check_per_input_us); - stats_current1_accum_population_per_input_us_(entry.population_per_input_us); - stats_current1_accum_accept_per_input_us_(entry.accept_per_input_us); - stats_current1_accum_connect_per_input_us_(entry.connect_per_input_us); - stats_current1_accum_deposit_per_input_us_(entry.deposit_per_input_us); - stats_current1_accum_cache_efficiency_(entry.cache_efficiency); - - stats_current2_accum_transactions_(entry.transactions); - stats_current2_accum_inputs_(entry.inputs); - stats_current2_accum_outputs_(entry.outputs); - stats_current2_accum_wait_total_ms_(entry.wait_total_ms); - stats_current2_accum_validation_total_ms_(entry.validation_total_ms); - stats_current2_accum_validation_per_input_us_(entry.validation_per_input_us); - stats_current2_accum_deserialization_per_input_us_(entry.deserialization_per_input_us); - stats_current2_accum_check_per_input_us_(entry.check_per_input_us); - stats_current2_accum_population_per_input_us_(entry.population_per_input_us); - stats_current2_accum_accept_per_input_us_(entry.accept_per_input_us); - stats_current2_accum_connect_per_input_us_(entry.connect_per_input_us); - stats_current2_accum_deposit_per_input_us_(entry.deposit_per_input_us); - stats_current2_accum_cache_efficiency_(entry.cache_efficiency); - - stats_total_accum_transactions_(entry.transactions); - stats_total_accum_inputs_(entry.inputs); - stats_total_accum_outputs_(entry.outputs); - stats_total_accum_wait_total_ms_(entry.wait_total_ms); - stats_total_accum_validation_total_ms_(entry.validation_total_ms); - stats_total_accum_validation_per_input_us_(entry.validation_per_input_us); - stats_total_accum_deserialization_per_input_us_(entry.deserialization_per_input_us); - stats_total_accum_check_per_input_us_(entry.check_per_input_us); - stats_total_accum_population_per_input_us_(entry.population_per_input_us); - stats_total_accum_accept_per_input_us_(entry.accept_per_input_us); - stats_total_accum_connect_per_input_us_(entry.connect_per_input_us); - stats_total_accum_deposit_per_input_us_(entry.deposit_per_input_us); - stats_total_accum_cache_efficiency_(entry.cache_efficiency); - } - - template - void collect_statistics(size_t height, Args&&... args) { - - // std::chrono::time_point time_from_block_0_; - // std::chrono::time_point time_from_last_10000_block_; - // std::chrono::time_point time_from_last_100000_block_; - - if (height == 1) { - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - printf("**********************************************************************\n"); - time_from_block_0_ = std::chrono::high_resolution_clock::now(); - time_from_last_10000_block_ = time_from_block_0_; - time_from_last_100000_block_ = time_from_block_0_; - } else { - if (height % accum_blocks_1_ == 0) { - print_statistics(height - 1); - } - } - - // auto r = statistics_detail_.try_emplace(height, statistics_entry{std::forward(args)...}); - // if (std::get<1>(r)) { - // update_accum(height, std::get<0>(r)->second); - // } - - statistics_entry entry{std::forward(args)...}; - update_accum(height, entry); - } +#if ! defined(__EMSCRIPTEN__) + /// P2P network node. + [[nodiscard]] + kth::network::p2p_node& network(); +#endif - //TODO(fernando): could be outside the class - void print_stat_item_sum(tabulate::Table& stats, size_t from, size_t to, - double accum_transactions, double accum_inputs, double accum_outputs, double accum_wait_total, - double accum_validation_total, double accum_validation_per_input, double accum_deserialization_per_input, - double accum_check_per_input, double accum_population_per_input, double accum_accept_per_input, - double accum_connect_per_input, double accum_deposit_per_input) const; - - //TODO(fernando): could be outside the class - void print_stat_item(tabulate::Table& stats, size_t from, size_t to, std::string const& cat, - double accum_transactions, double accum_inputs, double accum_outputs, double accum_wait_total, - double accum_validation_total, double accum_validation_per_input, double accum_deserialization_per_input, - double accum_check_per_input, double accum_population_per_input, double accum_accept_per_input, - double accum_connect_per_input, double accum_deposit_per_input) const; - - // //TODO(fernando): could be outside the class - // template - // void print_stat_item(tabulate::Table& stats, size_t from, size_t to, std::string const& cat, F f, - // accum_t accum_transactions, accum_t accum_inputs, accum_t accum_outputs, accum_t accum_wait_total, - // accum_t accum_validation_total, accum_t accum_validation_per_input, accum_t accum_deserialization_per_input, - // accum_t accum_check_per_input, accum_t accum_population_per_input, accum_t accum_accept_per_input, - // accum_t accum_connect_per_input, accum_t accum_deposit_per_input) const { - // stats.add_row({ - // fmt::format("{}-{}", from, to) - // , cat - // , fmt::format("{:f}", f(accum_transactions)) - // , fmt::format("{:f}", f(accum_inputs)) - // , fmt::format("{:f}", f(accum_outputs)) - // , fmt::format("{:f}", f(accum_wait_total)) - // , fmt::format("{:f}", f(accum_validation_total)) - // , fmt::format("{:f}", f(accum_validation_per_input)) - // , fmt::format("{:f}", f(accum_deserialization_per_input)) - // , fmt::format("{:f}", f(accum_check_per_input)) - // , fmt::format("{:f}", f(accum_population_per_input)) - // , fmt::format("{:f}", f(accum_accept_per_input)) - // , fmt::format("{:f}", f(accum_connect_per_input)) - // , fmt::format("{:f}", f(accum_deposit_per_input))}); - - // last(stats) - // .format() - // .hide_border_top(); - - - // // auto formatted = fmt::format("{} [{}-{}] {:f} txs {:f} ins {:f} outs " - // // "{:f} wms {:f} vms {:f} vus {:f} rus {:f} cus {:f} pus " - // // "{:f} aus {:f} sus {:f} dus {:f}", - // // cat, from, too, - // // f(stats_current1_accum_transactions_), - // // f(stats_current1_accum_inputs_), - // // f(stats_current1_accum_outputs_), - // // f(stats_current1_accum_wait_total_ms_), - // // f(stats_current1_accum_validation_total_ms_), - // // f(stats_current1_accum_validation_per_input_us_), - // // f(stats_current1_accum_deserialization_per_input_us_), - // // f(stats_current1_accum_check_per_input_us_), - // // f(stats_current1_accum_population_per_input_us_), - // // f(stats_current1_accum_accept_per_input_us_), - // // f(stats_current1_accum_connect_per_input_us_), - // // f(stats_current1_accum_deposit_per_input_us_), - // // f(stats_current1_accum_cache_efficiency_)); - - // // spdlog::info("[blockchain] {}", formatted); - // } - - void print_statistics(size_t height) const; + // Thread pools + // ------------------------------------------------------------------------- + /// Thread pool for blockchain operations (validation, DB). + [[nodiscard]] + threadpool& chain_thread_pool(); +#if ! defined(__EMSCRIPTEN__) + /// Thread pool for network operations (P2P, sockets). + [[nodiscard]] + threadpool& network_thread_pool(); #endif + // Subscriptions + // ------------------------------------------------------------------------- -protected: - /// Attach a node::session to the network, caller must start the session. - template - typename Session::ptr attach(Args&&... args) { - return std::make_shared(*this, std::forward(args)...); - } + using block_channel_ptr = blockchain::block_chain::block_channel_ptr; + using transaction_channel_ptr = blockchain::block_chain::transaction_channel_ptr; + using ds_proof_channel_ptr = blockchain::block_chain::ds_proof_channel_ptr; -#if ! defined(__EMSCRIPTEN__) - /// Override to attach specialized p2p sessions. - ////network::session_seed::ptr attach_seed_session() OVERRIDE_COND; - network::session_manual::ptr attach_manual_session() OVERRIDE_COND; - network::session_inbound::ptr attach_inbound_session() OVERRIDE_COND; - network::session_outbound::ptr attach_outbound_session() OVERRIDE_COND; - - /// Override to attach specialized node sessions. - virtual - session_header_sync::ptr attach_header_sync_session(); - - virtual - session_block_sync::ptr attach_block_sync_session(); -#endif + /// Subscribe to blockchain reorganization events. + [[nodiscard]] + block_channel_ptr subscribe_blockchain(); - ///For mining - blockchain::block_chain chain_; + /// Subscribe to transaction pool acceptance events. + [[nodiscard]] + transaction_channel_ptr subscribe_transaction(); -private: - using block_ptr_list = domain::message::block::ptr_list; + /// Subscribe to DSProof pool acceptance events. + [[nodiscard]] + ds_proof_channel_ptr subscribe_ds_proof(); -#if defined(KTH_STATISTICS_ENABLED) - static constexpr size_t screen_refresh = 100; - static constexpr size_t accum_blocks_1_ = 10'000; - static constexpr size_t accum_blocks_2_ = 100'000; + /// Unsubscribe from blockchain events. + void unsubscribe_blockchain(block_channel_ptr const& channel); - // using statistics_detail_t = std::unordered_map>; - // using statistics_accum_t = std::vector; -#endif + /// Unsubscribe from transaction events. + void unsubscribe_transaction(transaction_channel_ptr const& channel); + /// Unsubscribe from DSProof events. + void unsubscribe_ds_proof(ds_proof_channel_ptr const& channel); - bool handle_reorganized(code ec, size_t fork_height, block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr outgoing); - void handle_headers_synchronized(code const& ec, result_handler handler); - void handle_network_stopped(code const& ec, result_handler handler); - - void handle_started(code const& ec, result_handler handler); - void handle_running(code const& ec, result_handler handler); - void handle_running_chain(code const& ec, result_handler handler); - - -#if defined(KTH_STATISTICS_ENABLED) - // statistics_detail_t statistics_detail_; - // statistics_accum_t statistics_accum_; - - std::chrono::time_point time_from_block_0_; - std::chrono::time_point time_from_last_10000_block_; - std::chrono::time_point time_from_last_100000_block_; - - accum_t stats_current1_accum_transactions_; - accum_t stats_current1_accum_inputs_; - accum_t stats_current1_accum_outputs_; - accum_t stats_current1_accum_wait_total_ms_; - accum_t stats_current1_accum_validation_total_ms_; - accum_t stats_current1_accum_validation_per_input_us_; - accum_t stats_current1_accum_deserialization_per_input_us_; - accum_t stats_current1_accum_check_per_input_us_; - accum_t stats_current1_accum_population_per_input_us_; - accum_t stats_current1_accum_accept_per_input_us_; - accum_t stats_current1_accum_connect_per_input_us_; - accum_t stats_current1_accum_deposit_per_input_us_; - accum_t stats_current1_accum_cache_efficiency_; - - accum_t stats_current2_accum_transactions_; - accum_t stats_current2_accum_inputs_; - accum_t stats_current2_accum_outputs_; - accum_t stats_current2_accum_wait_total_ms_; - accum_t stats_current2_accum_validation_total_ms_; - accum_t stats_current2_accum_validation_per_input_us_; - accum_t stats_current2_accum_deserialization_per_input_us_; - accum_t stats_current2_accum_check_per_input_us_; - accum_t stats_current2_accum_population_per_input_us_; - accum_t stats_current2_accum_accept_per_input_us_; - accum_t stats_current2_accum_connect_per_input_us_; - accum_t stats_current2_accum_deposit_per_input_us_; - accum_t stats_current2_accum_cache_efficiency_; - - accum_t stats_total_accum_transactions_; - accum_t stats_total_accum_inputs_; - accum_t stats_total_accum_outputs_; - accum_t stats_total_accum_wait_total_ms_; - accum_t stats_total_accum_validation_total_ms_; - accum_t stats_total_accum_validation_per_input_us_; - accum_t stats_total_accum_deserialization_per_input_us_; - accum_t stats_total_accum_check_per_input_us_; - accum_t stats_total_accum_population_per_input_us_; - accum_t stats_total_accum_accept_per_input_us_; - accum_t stats_total_accum_connect_per_input_us_; - accum_t stats_total_accum_deposit_per_input_us_; - accum_t stats_total_accum_cache_efficiency_; -#endif + // Utilities + // ------------------------------------------------------------------------- - // These are thread safe. - check_list hashes_; - //blockchain::block_chain chain_; + /// Get the genesis block for a network. + [[nodiscard]] + static domain::chain::block get_genesis_block(domain::config::network network); -#if ! defined(__EMSCRIPTEN__) - uint32_t const protocol_maximum_; -#endif +private: + // Internal helpers + bool handle_reorganized(code ec, size_t fork_height, + block_const_ptr_list_const_ptr incoming, + block_const_ptr_list_const_ptr outgoing); - const node::settings& node_settings_; + // Configuration references (stored in configuration object) + node::settings const& node_settings_; blockchain::settings const& chain_settings_; + domain::config::network network_type_; -#if defined(__EMSCRIPTEN__) - threadpool threadpool_; + // Thread pool for blockchain operations (validation, DB) + threadpool chain_thread_pool_; - threadpool& thread_pool() { - return threadpool_; - } + // Core components (composition, not inheritance) +#if ! defined(__EMSCRIPTEN__) + kth::network::p2p_node network_; #endif + blockchain::block_chain chain_; }; } // namespace kth::node -#endif +#endif // KTH_NODE_FULL_NODE_HPP diff --git a/src/node/include/kth/node/protocols/protocol_block_in.hpp b/src/node/include/kth/node/protocols/protocol_block_in.hpp deleted file mode 100644 index 046ff092..00000000 --- a/src/node/include/kth/node/protocols/protocol_block_in.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_BLOCK_IN_HPP -#define KTH_NODE_PROTOCOL_BLOCK_IN_HPP - -#include -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -struct temp_compact_block { - domain::chain::header header; - std::vector transactions; -}; - -class full_node; - -struct KND_API protocol_block_in : network::protocol_timer, track { -public: - using ptr = std::shared_ptr; - - using compact_block_map = std::unordered_map; - /// Construct a block protocol instance. - protocol_block_in(full_node& network, network::channel::ptr channel, blockchain::safe_chain& chain); - - /// Start the protocol. - virtual void start(); - -private: - using hash_queue = std::queue; - - -#if defined(KTH_STATISTICS_ENABLED) - static - void report(domain::chain::block const& block, full_node& node); -#else - static - void report(domain::chain::block const& block); -#endif - - void send_get_blocks(hash_digest const& stop_hash); - void send_get_data(code const& ec, get_data_ptr message); - - bool handle_receive_block(code const& ec, block_const_ptr message); - bool handle_receive_compact_block(code const& ec, compact_block_const_ptr message); - bool handle_receive_block_transactions(code const& ec,block_transactions_const_ptr message); - bool handle_receive_headers(code const& ec, headers_const_ptr message); - bool handle_receive_inventory(code const& ec, inventory_const_ptr message); - bool handle_receive_not_found(code const& ec, not_found_const_ptr message); - void handle_store_block(code const& ec, block_const_ptr message); - void handle_fetch_block_locator(code const& ec, get_headers_ptr message, hash_digest const& stop_hash); - void handle_fetch_block_locator_compact_block(code const& ec, get_headers_ptr message, hash_digest const& stop_hash); - - void send_get_data_compact_block(code const& ec, hash_digest const& hash); - - void handle_timeout(code const& ec); - void handle_stop(code const& ec); - - void organize_block(block_const_ptr message); - - // These are thread safe. - full_node& node_; - blockchain::safe_chain& chain_; - const asio::duration block_latency_; - bool const headers_from_peer_; - bool const compact_from_peer_; - bool const blocks_from_peer_; - - // This is protected by mutex. - hash_queue backlog_; - mutable upgrade_mutex mutex; - - compact_block_map compact_blocks_map_; - - bool compact_blocks_high_bandwidth_set_; - - // TODO(Mario): compact blocks version 1 hardcoded, change to 2 when segwit is implemented -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/protocols/protocol_block_out.hpp b/src/node/include/kth/node/protocols/protocol_block_out.hpp deleted file mode 100644 index dfacb76c..00000000 --- a/src/node/include/kth/node/protocols/protocol_block_out.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_BLOCK_OUT_HPP -#define KTH_NODE_PROTOCOL_BLOCK_OUT_HPP - -#include -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -class full_node; - -struct KND_API protocol_block_out : network::protocol_events, track { -public: - using ptr = std::shared_ptr; - - /// Construct a block protocol instance. - protocol_block_out(full_node& network, network::channel::ptr channel, blockchain::safe_chain& chain); - - /// Start the protocol. - virtual void start(); - -private: - size_t locator_limit(); - - void send_next_data(inventory_ptr inventory); - void send_block(code const& ec, block_const_ptr message, size_t height, inventory_ptr inventory); - void send_merkle_block(code const& ec, merkle_block_const_ptr message, size_t height, inventory_ptr inventory); - void send_compact_block(code const& ec, compact_block_const_ptr message, size_t height, inventory_ptr inventory); - - bool handle_receive_get_data(code const& ec, get_data_const_ptr message); - bool handle_receive_get_blocks(code const& ec, get_blocks_const_ptr message); - bool handle_receive_get_headers(code const& ec, get_headers_const_ptr message); - bool handle_receive_send_headers(code const& ec, send_headers_const_ptr message); - bool handle_receive_send_compact(code const& ec, send_compact_const_ptr message); - - bool handle_receive_get_block_transactions(code const& ec, get_block_transactions_const_ptr message); - - void handle_fetch_locator_hashes(code const& ec, inventory_ptr message); - void handle_fetch_locator_headers(code const& ec, headers_ptr message); - - void handle_stop(code const& ec); - void handle_send_next(code const& ec, inventory_ptr inventory); - bool handle_reorganized(code ec, size_t fork_height, block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr outgoing); - - // These are thread safe. - full_node& node_; - blockchain::safe_chain& chain_; - kth::atomic last_locator_top_; - std::atomic compact_to_peer_; - std::atomic headers_to_peer_; - std::atomic compact_high_bandwidth_; - std::atomic compact_version_; -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/protocols/protocol_block_sync.hpp b/src/node/include/kth/node/protocols/protocol_block_sync.hpp deleted file mode 100644 index 6bc27d24..00000000 --- a/src/node/include/kth/node/protocols/protocol_block_sync.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_BLOCK_SYNC_HPP -#define KTH_NODE_PROTOCOL_BLOCK_SYNC_HPP - -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -class full_node; - -/// Blocks sync protocol, thread safe. -struct KND_API protocol_block_sync : network::protocol_timer, track { -public: - using ptr = std::shared_ptr; - - /// Construct a block sync protocol instance. - protocol_block_sync(full_node& network, network::channel::ptr channel, reservation::ptr row); - - /// Start the protocol. - virtual void start(event_handler handler); - -private: - void send_get_blocks(event_handler complete, bool reset); - void handle_event(code const& ec, event_handler complete); - void blocks_complete(code const& ec, event_handler handler); - bool handle_receive_block(code const& ec, block_const_ptr message, event_handler complete); - - reservation::ptr reservation_; -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/protocols/protocol_double_spend_proof_in.hpp b/src/node/include/kth/node/protocols/protocol_double_spend_proof_in.hpp deleted file mode 100644 index 7d49b3e5..00000000 --- a/src/node/include/kth/node/protocols/protocol_double_spend_proof_in.hpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_double_spend_proof_IN_HPP -#define KTH_NODE_PROTOCOL_double_spend_proof_IN_HPP - -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -class full_node; - -struct KND_API protocol_double_spend_proof_in : network::protocol_events, track { -public: - using ptr = std::shared_ptr; - - /// Construct a _double spend proofs protocol instance. - protocol_double_spend_proof_in(full_node& network, network::channel::ptr channel, blockchain::safe_chain& chain); - - /// Start the protocol. - virtual void start(); - -private: - void send_get_data(code const& ec, get_data_ptr message); - - bool handle_receive_inventory(code const& ec, inventory_const_ptr message); - bool handle_receive_ds_proof_data(code const& ec, double_spend_proof_const_ptr message); - void handle_store_ds_proof_data(code const& ec, double_spend_proof_const_ptr message); - void handle_stop(code const&); - - // These are thread safe. - blockchain::safe_chain& chain_; - bool const ds_proofs_enabled_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_PROTOCOL_double_spend_proof_IN_HPP diff --git a/src/node/include/kth/node/protocols/protocol_double_spend_proof_out.hpp b/src/node/include/kth/node/protocols/protocol_double_spend_proof_out.hpp deleted file mode 100644 index ace4f265..00000000 --- a/src/node/include/kth/node/protocols/protocol_double_spend_proof_out.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_double_spend_proof_OUT_HPP -#define KTH_NODE_PROTOCOL_double_spend_proof_OUT_HPP - -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -class full_node; - -struct KND_API protocol_double_spend_proof_out : network::protocol_events, track { -public: - using ptr = std::shared_ptr; - - /// Construct a DSProof protocol instance. - protocol_double_spend_proof_out(full_node& network, network::channel::ptr channel, blockchain::safe_chain& chain); - - /// Start the protocol. - virtual void start(); - -private: - void send_next_data(inventory_ptr inventory); - void send_ds_proof(code const& ec, double_spend_proof_const_ptr message, inventory_ptr inventory); - - bool handle_receive_get_data(code const& ec, get_data_const_ptr message); - void handle_stop(code const& ec); - void handle_send_next(code const& ec, inventory_ptr inventory); - bool handle_ds_proof_pool(code const& ec, double_spend_proof_const_ptr message); - - // These are thread safe. - blockchain::safe_chain& chain_; - bool const ds_proofs_enabled_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_PROTOCOL_double_spend_proof_OUT_HPP diff --git a/src/node/include/kth/node/protocols/protocol_header_sync.hpp b/src/node/include/kth/node/protocols/protocol_header_sync.hpp deleted file mode 100644 index df1b8046..00000000 --- a/src/node/include/kth/node/protocols/protocol_header_sync.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_HEADER_SYNC_HPP -#define KTH_NODE_PROTOCOL_HEADER_SYNC_HPP - -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include - -namespace kth::node { - -class full_node; - -/// Headers sync protocol, thread safe. -struct KND_API protocol_header_sync : network::protocol_timer, track { -public: - using ptr = std::shared_ptr; - - /// Construct a header sync protocol instance. - protocol_header_sync(full_node& network, network::channel::ptr channel, header_list::ptr headers, uint32_t minimum_rate); - - /// Start the protocol. - virtual void start(event_handler handler); - -private: - void send_get_headers(event_handler complete); - void handle_event(code const& ec, event_handler complete); - void headers_complete(code const& ec, event_handler handler); - bool handle_receive_headers(code const& ec, headers_const_ptr message, event_handler complete); - - // Thread safe and guarded by sequential header sync. - header_list::ptr headers_; - - // This is guarded by protocol_timer/deadline contract (exactly one call). - size_t current_second_; - - uint32_t const minimum_rate_; - size_t const start_size_; -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/protocols/protocol_transaction_in.hpp b/src/node/include/kth/node/protocols/protocol_transaction_in.hpp deleted file mode 100644 index 78649dac..00000000 --- a/src/node/include/kth/node/protocols/protocol_transaction_in.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_TRANSACTION_IN_HPP -#define KTH_NODE_PROTOCOL_TRANSACTION_IN_HPP - -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -class full_node; - -struct KND_API protocol_transaction_in : network::protocol_events, track { -public: - using ptr = std::shared_ptr; - - /// Construct a transaction protocol instance. - protocol_transaction_in(full_node& network, network::channel::ptr channel, blockchain::safe_chain& chain); - - /// Start the protocol. - virtual void start(); - -private: - void send_get_transactions(transaction_const_ptr message); - void send_get_data(code const& ec, get_data_ptr message); - - bool handle_receive_inventory(code const& ec, inventory_const_ptr message); - bool handle_receive_transaction(code const& ec, transaction_const_ptr message); - void handle_store_transaction(code const& ec, transaction_const_ptr message); - - void handle_stop(code const&); - - // These are thread safe. - blockchain::safe_chain& chain_; - uint64_t const minimum_relay_fee_; - bool const relay_from_peer_; - bool const refresh_pool_; -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/protocols/protocol_transaction_out.hpp b/src/node/include/kth/node/protocols/protocol_transaction_out.hpp deleted file mode 100644 index 89378eea..00000000 --- a/src/node/include/kth/node/protocols/protocol_transaction_out.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PROTOCOL_TRANSACTION_OUT_HPP -#define KTH_NODE_PROTOCOL_TRANSACTION_OUT_HPP - -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -class full_node; - -struct KND_API protocol_transaction_out : network::protocol_events, track { -public: - using ptr = std::shared_ptr; - - /// Construct a transaction protocol instance. - protocol_transaction_out(full_node& network, network::channel::ptr channel, blockchain::safe_chain& chain); - - /// Start the protocol. - virtual void start(); - -private: - void send_next_data(inventory_ptr inventory); - void send_transaction(code const& ec, transaction_const_ptr message, size_t position, size_t height, inventory_ptr inventory); - - bool handle_receive_get_data(code const& ec, get_data_const_ptr message); - bool handle_receive_fee_filter(code const& ec, fee_filter_const_ptr message); - bool handle_receive_memory_pool(code const& ec, memory_pool_const_ptr message); - void handle_fetch_mempool(code const& ec, inventory_ptr message); - void handle_stop(code const& ec); - void handle_send_next(code const& ec, inventory_ptr inventory); - bool handle_transaction_pool(code const& ec, transaction_const_ptr message); - - // These are thread safe. - blockchain::safe_chain& chain_; - std::atomic minimum_peer_fee_; - bool const relay_to_peer_; - // bool const enable_witness_; -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/sessions/session.hpp b/src/node/include/kth/node/sessions/session.hpp deleted file mode 100644 index 81e4002c..00000000 --- a/src/node/include/kth/node/sessions/session.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_SESSION_HPP -#define KTH_NODE_SESSION_HPP - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -namespace kth::node { - -class full_node; - -/// Intermediate session base class template. -/// This avoids having to make network::session into a template. -template -struct KND_API session : Session { -protected: - /// Construct an instance. - session(full_node& node, bool notify_on_connect) - : Session(node, notify_on_connect), node_(node) {} - - /// Attach a protocol to a channel, caller must start the channel. - template - typename Protocol::ptr attach(network::channel::ptr channel, Args&&... args) { - return std::make_shared(node_, channel, std::forward(args)...); - } - -private: - // This is thread safe. - full_node& node_; -}; - -} // namespace kth::node - -#endif diff --git a/src/node/include/kth/node/sessions/session_block_sync.hpp b/src/node/include/kth/node/sessions/session_block_sync.hpp deleted file mode 100644 index 283bb3f4..00000000 --- a/src/node/include/kth/node/sessions/session_block_sync.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_SESSION_BLOCK_SYNC_HPP -#define KTH_NODE_SESSION_BLOCK_SYNC_HPP - -#include -#include -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif - -#include -#include -#include -#include - -namespace kth::node { - -class full_node; - -/// Class to manage initial block download connections, thread safe. -struct KND_API session_block_sync : session, track { -public: - using ptr = std::shared_ptr; - - session_block_sync(full_node& network, check_list& hashes, blockchain::fast_chain& chain, settings const& settings); - - void start(result_handler handler) override; - -protected: - /// Overridden to attach and start specialized handshake. - void attach_handshake_protocols(network::channel::ptr channel, result_handler handle_started) override; - - /// Override to attach and start specialized protocols after handshake. - virtual void attach_protocols(network::channel::ptr channel, reservation::ptr row, result_handler handler); - -private: - void handle_started(code const& ec, result_handler handler); - void new_connection(reservation::ptr row, result_handler handler); - - // Sequence. - void handle_connect(code const& ec, network::channel::ptr channel, reservation::ptr row, result_handler handler); - void handle_channel_start(code const& ec, network::channel::ptr channel, reservation::ptr row, result_handler handler); - void handle_channel_complete(code const& ec, reservation::ptr row, result_handler handler); - void handle_channel_stop(code const& ec, reservation::ptr row); - void handle_complete(code const& ec, result_handler handler); - - // Timers. - void reset_timer(); - void handle_timer(code const& ec); - - // These are thread safe. - blockchain::fast_chain& chain_; - reservations reservations_; - deadline::ptr timer_; -}; - -} // namespace kth::node - -#endif - diff --git a/src/node/include/kth/node/sessions/session_header_sync.hpp b/src/node/include/kth/node/sessions/session_header_sync.hpp deleted file mode 100644 index b64b34a9..00000000 --- a/src/node/include/kth/node/sessions/session_header_sync.hpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_SESSION_HEADER_SYNC_HPP -#define KTH_NODE_SESSION_HEADER_SYNC_HPP - -#include -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif - -#include -#include -#include - -namespace kth::node { - -class full_node; - -/// Class to manage initial header download connection, thread safe. -struct KND_API session_header_sync : session, track { -public: - using ptr = std::shared_ptr; - - session_header_sync(full_node& network, check_list& hashes, blockchain::fast_chain& blockchain, infrastructure::config::checkpoint::list const& checkpoints); - - virtual void start(result_handler handler) override; - -protected: - /// Overridden to attach and start specialized handshake. - void attach_handshake_protocols(network::channel::ptr channel, result_handler handle_started) override; - - /// Override to attach and start specialized protocols after handshake. - virtual void attach_protocols(network::channel::ptr channel, header_list::ptr headers, result_handler handler); - -private: - using headers_table = std::vector; - - bool initialize(); - void handle_started(code const& ec, result_handler handler); - void new_connection(header_list::ptr row, result_handler handler); - void start_syncing(code const& ec, infrastructure::config::authority const& host, result_handler handler); - - void handle_connect(code const& ec, network::channel::ptr channel, header_list::ptr row, result_handler handler); - void handle_complete(code const& ec, header_list::ptr row, result_handler handler); - void handle_channel_start(code const& ec, network::channel::ptr channel, header_list::ptr row, result_handler handler); - void handle_channel_stop(code const& ec, header_list::ptr row); - - // Thread safe. - check_list& hashes_; - - // These do not require guard because they are not used concurrently. - headers_table headers_; - uint32_t minimum_rate_; - blockchain::fast_chain& chain_; - infrastructure::config::checkpoint::list const checkpoints_; -}; - -} // namespace kth::node - -#endif - diff --git a/src/node/include/kth/node/sessions/session_inbound.hpp b/src/node/include/kth/node/sessions/session_inbound.hpp deleted file mode 100644 index c0c61758..00000000 --- a/src/node/include/kth/node/sessions/session_inbound.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_SESSION_INBOUND_HPP -#define KTH_NODE_SESSION_INBOUND_HPP - -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif - -namespace kth::node { - -class full_node; - -/// Inbound connections session, thread safe. -struct KND_API session_inbound : session, track { -public: - using ptr = std::shared_ptr; - - /// Construct an instance. - session_inbound(full_node& network, blockchain::safe_chain& chain); - -protected: - /// Overridden to attach blockchain protocols. - void attach_protocols(network::channel::ptr channel) override; - - blockchain::safe_chain& chain_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_SESSION_INBOUND_HPP diff --git a/src/node/include/kth/node/sessions/session_manual.hpp b/src/node/include/kth/node/sessions/session_manual.hpp deleted file mode 100644 index acc3c5a1..00000000 --- a/src/node/include/kth/node/sessions/session_manual.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_SESSION_MANUAL_HPP -#define KTH_NODE_SESSION_MANUAL_HPP - -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -class full_node; - -/// Manual connections session, thread safe. -struct KND_API session_manual : session, track { -public: - using ptr = std::shared_ptr; - - /// Construct an instance. - session_manual(full_node& network, blockchain::safe_chain& chain); - -protected: - /// Overridden to attach blockchain protocols. - void attach_protocols(network::channel::ptr channel) override; - - blockchain::safe_chain& chain_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_SESSION_MANUAL_HPP diff --git a/src/node/include/kth/node/sessions/session_outbound.hpp b/src/node/include/kth/node/sessions/session_outbound.hpp deleted file mode 100644 index 6d70c947..00000000 --- a/src/node/include/kth/node/sessions/session_outbound.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_SESSION_OUTBOUND_HPP -#define KTH_NODE_SESSION_OUTBOUND_HPP - -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -class full_node; - -/// Outbound connections session, thread safe. -struct KND_API session_outbound : session, track { -public: - using ptr = std::shared_ptr; - - /// Construct an instance. - session_outbound(full_node& network, blockchain::safe_chain& chain); - -protected: - /// Overridden to attach blockchain protocols. - void attach_protocols(network::channel::ptr channel) override; - - blockchain::safe_chain& chain_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_SESSION_OUTBOUND_HPP diff --git a/src/node/include/kth/node/settings.hpp b/src/node/include/kth/node/settings.hpp index 34d34236..5a29f5c9 100644 --- a/src/node/include/kth/node/settings.hpp +++ b/src/node/include/kth/node/settings.hpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace kth::node { @@ -24,6 +25,9 @@ struct KND_API settings { bool compact_blocks_high_bandwidth; bool ds_proofs_enabled; + /// Display mode for console output (tui, log, daemon) + display_mode display{display_mode::log}; + /// Helpers. asio::duration block_latency() const; }; diff --git a/src/node/include/kth/node/sync_session.hpp b/src/node/include/kth/node/sync_session.hpp new file mode 100644 index 00000000..7ccb12b5 --- /dev/null +++ b/src/node/include/kth/node/sync_session.hpp @@ -0,0 +1,147 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_SYNC_SESSION_HPP +#define KTH_NODE_SYNC_SESSION_HPP + +// ============================================================================= +// Sync Session - Headers-First Block Synchronization +// ============================================================================= +// +// This class coordinates the headers-first synchronization protocol: +// +// SYNC FLOW: +// ---------- +// 1. Build block locator from current chain state +// 2. Send getheaders to peer, receive headers +// 3. Validate and store headers (via header_organizer) +// 4. Request blocks for validated headers (getdata) +// 5. Receive and organize blocks +// 6. Repeat until synced with peer +// +// HEADERS-FIRST BENEFITS: +// ----------------------- +// - Lower bandwidth: Headers are ~80 bytes vs full blocks (MB) +// - Faster validation: Can validate PoW chain before downloading blocks +// - Parallel downloads: Can request blocks from multiple peers +// +// ARCHITECTURE: +// ------------- +// Uses coroutines for async I/O with peer_session. +// Delegates header caching and validation to header_organizer. +// Interacts with blockchain via block_chain::organize(). +// +// ============================================================================= + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace kth::node { + +/// Configuration for sync session +struct sync_config { + /// Maximum headers to request per getheaders + size_t max_headers_per_request{2000}; + + /// Maximum blocks to request per getdata + size_t max_blocks_per_request{16}; + + /// Timeout for header requests + std::chrono::seconds headers_timeout{30}; + + /// Timeout for block requests + std::chrono::seconds block_timeout{60}; + + /// Minimum peer protocol version for headers-first sync + uint32_t minimum_version{70012}; +}; + +/// Result of a sync operation +struct sync_result { + code error; + size_t headers_received{0}; + size_t blocks_received{0}; + size_t final_height{0}; +}; + +/// Sync session - coordinates headers-first sync with a single peer +class KND_API sync_session { +public: + using ptr = std::shared_ptr; + + /// Construct sync session + sync_session( + blockchain::block_chain& chain, + network::peer_session::ptr peer, + domain::config::network network, + sync_config const& config = {}); + + /// Run synchronization with peer + /// Returns when synced or on error + [[nodiscard]] + ::asio::awaitable run(); + + /// Check if sync is complete (peer has no more headers) + [[nodiscard]] + bool is_synced() const; + + /// Get current sync heights (header_height, block_height) + [[nodiscard]] + std::pair current_heights() const; + +private: + // Build block locator for getheaders + hash_list build_locator() const; + + // Sync phases + // Fetch headers and add to organizer, returns hashes for block download + ::asio::awaitable sync_headers_batch(); + ::asio::awaitable sync_blocks(std::vector const& hashes); + + blockchain::block_chain& chain_; + blockchain::header_organizer organizer_; + network::peer_session::ptr peer_; + sync_config config_; + + size_t header_height_{0}; // Current header-sync height (from DB at start) + size_t block_height_{0}; // Current block-sync height + size_t target_height_{0}; // Peer's start_height from version message + hash_digest last_header_hash_{null_hash}; + bool synced_{false}; + + // Statistics + size_t total_headers_{0}; + size_t total_blocks_{0}; +}; + +/// Create a sync session for a peer +[[nodiscard]] +KND_API sync_session::ptr make_sync_session( + blockchain::block_chain& chain, + network::peer_session::ptr peer, + domain::config::network network, + sync_config const& config = {}); + +/// Run sync with the best available peer +/// Selects peer based on start_height from version message +[[nodiscard]] +KND_API ::asio::awaitable sync_from_best_peer( + blockchain::block_chain& chain, + network::p2p_node& p2p, + domain::config::network network, + sync_config const& config = {}); + +} // namespace kth::node + +#endif // KTH_NODE_SYNC_SESSION_HPP diff --git a/src/node/include/kth/node/utility/reservation.hpp b/src/node/include/kth/node/utility/reservation.hpp index 30dbbce5..666efc91 100644 --- a/src/node/include/kth/node/utility/reservation.hpp +++ b/src/node/include/kth/node/utility/reservation.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,7 @@ namespace kth::node { class reservations; // Class to manage hashes during sync, thread safe. -struct KND_API reservation : enable_shared_from_base { +struct KND_API reservation : kth::enable_shared_from_base { public: using ptr = std::shared_ptr; using list = std::vector; diff --git a/src/node/include/kth/node/utility/reservations.hpp b/src/node/include/kth/node/utility/reservations.hpp index 49279d1f..ad7a20e6 100644 --- a/src/node/include/kth/node/utility/reservations.hpp +++ b/src/node/include/kth/node/utility/reservations.hpp @@ -30,7 +30,7 @@ struct KND_API reservations { /// Construct a reservation table of reservations, allocating hashes evenly /// among the rows up to the limit of a single get headers p2p request. - reservations(check_list& hashes, blockchain::fast_chain& chain, settings const& settings); + reservations(check_list& hashes, blockchain::block_chain& chain, settings const& settings); /// Set the flush lock guard. bool start(); @@ -82,7 +82,7 @@ struct KND_API reservations { uint32_t const timeout_; // Protected by block exclusivity and limited call scope. - blockchain::fast_chain& chain_; + blockchain::block_chain& chain_; // Protected by mutex. reservation::list table_; diff --git a/src/node/src/executor/executor.cpp b/src/node/src/executor/executor.cpp index abc7e9f5..c183e885 100644 --- a/src/node/src/executor/executor.cpp +++ b/src/node/src/executor/executor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -19,6 +20,8 @@ #include #include +#include +#include #include #include @@ -64,6 +67,17 @@ executor::executor(kth::node::configuration const& config, bool stdout_enabled / #endif // ! defined(__EMSCRIPTEN__) } +executor::~executor() { + if (running_) { + signal_stop(); + } + // Ensure io_context is stopped and thread is joined + io_context_.stop(); + if (io_thread_.joinable()) { + io_thread_.join(); + } +} + void executor::print_version(std::string_view extra) { std::println(KTH_VERSION_MESSAGE, kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); } @@ -74,9 +88,12 @@ bool executor::init_directory(error_code& ec) { if (create_directories(directory, ec)) { spdlog::info("[node] {}", fmt::format(KTH_INITIALIZING_CHAIN, directory.string())); + auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); auto const& settings = config_.database; - auto const result = data_base(settings).create(genesis); + + data_base db(settings); + auto const result = db.create(genesis); if ( ! result ) { spdlog::info("[node] {}", KTH_INITCHAIN_FAILED); @@ -125,14 +142,20 @@ kth::node::full_node const& executor::node() const { bool executor::close() { spdlog::info("[node] {}", KTH_NODE_STOPPING); - // Close must be called from main thread. - if (node_->close()) { + if (node_) { + node_->stop(); + node_->join(); spdlog::info("[node] {}", KTH_NODE_STOPPED); - spdlog::info("[node] {}", KTH_GOOD_BYE); - } else { - spdlog::info("[node] {}", KTH_NODE_STOP_FAIL); } + // Stop the io_context and wait for the io thread to finish + io_context_.stop(); + if (io_thread_.joinable()) { + io_thread_.join(); + } + + spdlog::info("[node] {}", KTH_GOOD_BYE); + running_ = false; return true; } @@ -154,15 +177,53 @@ error_code executor::init_directory_if_necessary() { return ec; } -bool executor::init_run_and_wait_for_signal(std::string_view extra, start_modules mods, kth::handle0 handler) { +// Helper to run node in coroutine context +void executor::run_node_async(start_modules mod) { + ::asio::co_spawn(io_context_, [this, mod]() -> ::asio::awaitable { + // Start the node + auto start_ec = co_await node_->start(); + if (start_ec != error::success) { + spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, start_ec.message())); + if (run_handler_) { + run_handler_(start_ec); + } + co_return; + } + + spdlog::info("[node] {}", KTH_NODE_SEEDED); + + // Run the node (only for full mode, not just_chain) + if (mod != start_modules::just_chain) { + auto run_ec = co_await node_->run(); + if (run_ec != error::success) { + spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, run_ec.message())); + if (run_handler_) { + run_handler_(run_ec); + } + co_return; + } + } + + spdlog::info("[node] {}", KTH_NODE_STARTED); + + if (run_handler_) { + run_handler_(error::success); + } + }, ::asio::detached); + + // Run the io_context in a background thread (saved for proper shutdown) + io_thread_ = std::thread([this]() { + io_context_.run(); + }); +} + +bool executor::init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler) { run_handler_ = std::move(handler); initialize_output(extra, config_.database.db_mode); spdlog::info("[node] {}", KTH_NODE_INTERRUPT); spdlog::info("[node] {}", KTH_NODE_STARTING); - //TODO(fernando): Log Cryptocurrency - //TODO(fernando): Log Microarchitecture auto ec = init_directory_if_necessary(); if (ec != error::success) { @@ -178,27 +239,22 @@ bool executor::init_run_and_wait_for_signal(std::string_view extra, start_module // Now that the directory is verified we can create the node for it. node_ = std::make_shared(config_); + running_ = true; - // The callback may be returned on the same thread. - if (mods == start_modules::just_chain) { - node_->start_chain(std::bind(&executor::handle_started, this, _1, mods)); - } else { - node_->start(std::bind(&executor::handle_started, this, _1, mods)); - } + // Start and run the node asynchronously + run_node_async(mod); auto res = wait_for_signal_and_close(); return res; } -bool executor::init_run(std::string_view extra, start_modules mods, kth::handle0 handler) { +bool executor::init_run(std::string_view extra, start_modules mod, kth::handle0 handler) { run_handler_ = std::move(handler); initialize_output(extra, config_.database.db_mode); spdlog::info("[node] {}", KTH_NODE_INTERRUPT); spdlog::info("[node] {}", KTH_NODE_STARTING); - //TODO(fernando): Log Cryptocurrency - //TODO(fernando): Log Microarchitecture auto ec = init_directory_if_necessary(); if (ec != error::success) { @@ -213,70 +269,18 @@ bool executor::init_run(std::string_view extra, start_modules mods, kth::handle0 // Now that the directory is verified we can create the node for it. node_ = std::make_shared(config_); + running_ = true; - // The callback may be returned on the same thread. - if (mods == start_modules::just_chain) { - node_->start_chain(std::bind(&executor::handle_started, this, _1, mods)); - } else { - node_->start(std::bind(&executor::handle_started, this, _1, mods)); - } + // Start and run the node asynchronously + run_node_async(mod); return true; } #endif // ! defined(KTH_DB_READONLY) -// Handle the completion of the start sequence and begin the run sequence. -void executor::handle_started(kth::code const& ec, start_modules mods) { - if (ec) { - spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, ec.message())); -// stop(ec); - - if (run_handler_) { - run_handler_(ec); - } - return; - } - - if (mods == start_modules::just_chain) { - node_->run_chain(std::bind(&executor::handle_running, this, _1)); - } else { - spdlog::info("[node] {}", KTH_NODE_SEEDED); - // This is the beginning of the stop sequence. - node_->subscribe_stop(std::bind(&executor::handle_stopped, this, _1)); - // This is the beginning of the run sequence. - node_->run(std::bind(&executor::handle_running, this, _1)); - } -} - -// This is the end of the run sequence. -void executor::handle_running(kth::code const& ec) { - if (ec) { - spdlog::info("[node] {}", fmt::format(KTH_NODE_START_FAIL, ec.message())); -// stop(ec); - - if (run_handler_) { - run_handler_(ec); - } - - return; - } - - spdlog::info("[node] {}", KTH_NODE_STARTED); - - if (run_handler_) { - run_handler_(ec); - } -} - bool executor::stopped() const { - return node_->stopped(); -} - -// This is the end of the stop sequence. -void executor::handle_stopped(kth::code const& /*ec*/) { - //stop(ec); - //stop(); + return node_ ? node_->stopped() : true; } // Stop signal. diff --git a/src/node/src/full_node.cpp b/src/node/src/full_node.cpp index fe7e374f..f46f3a73 100644 --- a/src/node/src/full_node.cpp +++ b/src/node/src/full_node.cpp @@ -6,37 +6,18 @@ #include #include -#include -#include +#include #include + #include #include #include +#include -#if ! defined(__EMSCRIPTEN__) -#include -#include -#include -#include -#include -#endif - -#if defined(KTH_STATISTICS_ENABLED) -#include - -tabulate::Row& last(tabulate::Table& table) { - auto const l = table.end(); - auto f = table.begin(); - auto p = f; - ++f; - - while (f != l) { - p = f; - ++f; - } - return *p; -} -#endif +#include +#include +#include +#include namespace kth::node { @@ -48,356 +29,311 @@ using namespace kth::domain::config; using namespace kth::network; #endif -using namespace std::placeholders; +// ============================================================================= +// Construction +// ============================================================================= full_node::full_node(configuration const& configuration) #if ! defined(__EMSCRIPTEN__) : multi_crypto_setter(configuration.network) - , p2p(configuration.network) -#else - : multi_crypto_setter() -#endif - -#if ! defined(__EMSCRIPTEN__) + , node_settings_(configuration.node) + , chain_settings_(configuration.chain) + , network_type_(get_network(configuration.network.identifier, configuration.network.inbound_port == 48333)) + , chain_thread_pool_(configuration.chain.cores) + , network_(configuration.network) , chain_( - thread_pool() - , configuration.chain - , configuration.database - , get_network(configuration.network.identifier, configuration.network.inbound_port == 48333) - , configuration.network.relay_transactions + chain_thread_pool_, + configuration.chain, + configuration.database, + network_type_, + configuration.network.relay_transactions ) #else + : multi_crypto_setter() + , node_settings_(configuration.node) + , chain_settings_(configuration.chain) + , network_type_(domain::config::network::mainnet) + , chain_thread_pool_(std::thread::hardware_concurrency()) , chain_( - thread_pool() - , configuration.chain - , configuration.database - , domain::config::network::mainnet + chain_thread_pool_, + configuration.chain, + configuration.database, + network_type_ ) #endif - -#if ! defined(__EMSCRIPTEN__) - , protocol_maximum_(configuration.network.protocol_maximum) -#endif - , chain_settings_(configuration.chain) - , node_settings_(configuration.node) - -#if defined(__EMSCRIPTEN__) - , threadpool_("") -#endif {} full_node::~full_node() { - full_node::close(); + stop(); + join(); } -// Start. -// ---------------------------------------------------------------------------- - -void full_node::start(result_handler handler) { - if ( ! stopped()) { - handler(error::operation_failed); - return; - } - - if ( ! chain_.start()) { - spdlog::error("[node] Failure starting blockchain [full_node::start()]."); - handler(error::operation_failed); - return; - } - - // This is invoked on the same thread. - // Stopped is true and no network threads until after this call. - p2p::start(handler); -} +// ============================================================================= +// Lifecycle +// ============================================================================= -void full_node::start_chain(result_handler handler) { - if ( ! stopped()) { - handler(error::operation_failed); - return; +::asio::awaitable full_node::start() { +#if ! defined(__EMSCRIPTEN__) + if (!stopped()) { + co_return error::operation_failed; } +#endif - if ( ! chain_.start()) { - spdlog::error("[node] Failure starting blockchain [full_node::start_chain()]."); - handler(error::operation_failed); - return; + // Start the blockchain + if (!chain_.start()) { + spdlog::error("[node] Failure starting blockchain."); + co_return error::operation_failed; } - std::thread t1([this, handler] { - p2p::start_fake(handler); - }); - t1.detach(); -} - -// Run sequence. -// ---------------------------------------------------------------------------- - -void full_node::run(result_handler handler) { - if (stopped()) { - handler(error::service_stopped); - return; +#if ! defined(__EMSCRIPTEN__) + // Start the P2P network + auto ec = co_await network_.start(); + if (ec != error::success) { + spdlog::error("[node] Failure starting network: {}", ec.message()); + chain_.stop(); + co_return ec; } +#endif - // Skip sync sessions. - handle_running(error::success, handler); - return; - - // TODO: make this safe by requiring sync if gaps found. - ////// By setting no download connections checkpoints can be used without sync. - ////// This also allows the maximum protocol version to be set below headers. - ////if (settings_.sync_peers == 0) - ////{ - //// // This will spawn a new thread before returning. - //// handle_running(error::success, handler); - //// return; - ////} - - ////// The instance is retained by the stop handler (i.e. until shutdown). - ////auto const header_sync = attach_header_sync_session(); - - ////// This is invoked on a new thread. - ////header_sync->start( - //// std::bind(&full_node::handle_headers_synchronized, - //// this, _1, handler)); + spdlog::info("[node] Node started successfully."); + co_return error::success; } -void full_node::run_chain(result_handler handler) { +::asio::awaitable full_node::run() { +#if ! defined(__EMSCRIPTEN__) if (stopped()) { - handler(error::service_stopped); - return; + co_return error::service_stopped; } +#endif - // Skip sync sessions. - handle_running_chain(error::success, handler); - return; -} - -void full_node::handle_headers_synchronized(code const& ec, result_handler handler) { - ////if (stopped()) - ////{ - //// handler(error::service_stopped); - //// return; - ////} - - ////if (ec) - ////{ - //// spdlog::error("[node] - ////] Failure synchronizing headers: {}", ec.message()); - //// handler(ec); - //// return; - ////} - - ////// The instance is retained by the stop handler (i.e. until shutdown). - ////auto const block_sync = attach_block_sync_session(); - - ////// This is invoked on a new thread. - ////block_sync->start( - //// std::bind(&full_node::handle_running, - //// this, _1, handler)); -} - -void full_node::handle_running(code const& ec, result_handler handler) { - if (stopped()) { - handler(error::service_stopped); - return; + // Get current chain heights + auto const heights = chain_.get_last_heights(); + if ( ! heights) { + spdlog::error("[node] The blockchain is corrupt."); + co_return error::operation_failed; } + auto const [header_height, block_height] = *heights; - if (ec) { - spdlog::error("[node] Failure synchronizing blocks: {}", ec.message()); - handler(ec); - return; + auto const top_hash = chain_.get_block_hash(block_height); + if ( ! top_hash) { + spdlog::error("[node] The blockchain is corrupt."); + co_return error::operation_failed; } - size_t top_height; - hash_digest top_hash; +#if ! defined(__EMSCRIPTEN__) + network_.set_top_block({*top_hash, block_height}); +#endif - if ( ! chain_.get_last_height(top_height) || - ! chain_.get_block_hash(top_hash, top_height)) { - spdlog::error("[node] The blockchain is corrupt."); - handler(error::operation_failed); - return; + spdlog::info("[node] Node start heights: header-sync ({}), block-sync ({}).", header_height, block_height); + + // Subscribe to blockchain reorganizations + auto blockchain_channel = subscribe_blockchain(); + if (blockchain_channel) { + ::asio::co_spawn(chain_.executor(), [this, blockchain_channel]() -> ::asio::awaitable { + while (blockchain_channel->is_open() && !stopped()) { + auto result = co_await blockchain_channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + auto& [ec, fork_height, incoming, outgoing] = result; + + if (ec) { + break; + } + + if ( ! handle_reorganized(error::success, fork_height, incoming, outgoing)) { + unsubscribe_blockchain(blockchain_channel); + break; + } + } + }, ::asio::detached); } - set_top_block({ std::move(top_hash), top_height }); - - spdlog::info("[node] Node start height is ({}).", top_height); +#if ! defined(__EMSCRIPTEN__) + // Run the P2P network (starts connections and protocol handlers) + auto ec = co_await network_.run(); + if (ec != error::success) { + spdlog::error("[node] Failure running network: {}", ec.message()); + co_return ec; + } - subscribe_blockchain( - std::bind(&full_node::handle_reorganized, this, _1, _2, _3, _4)); + // Start sync in background + // TODO(fernando): Make this configurable and add proper sync management + // TODO(fernando): blockchain::block_chain should migrate to coroutines + // (organize, fetch_*, etc.) to eliminate callbacks and std::promise usage + ::asio::co_spawn(network_.thread_pool().get_executor(), + [this]() -> ::asio::awaitable { + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + // Wait until we have at least one connected peer + while (!stopped() && network_.connection_count() == 0) { + timer.expires_after(std::chrono::milliseconds(500)); + co_await timer.async_wait(::asio::use_awaitable); + } + + if (stopped()) { + co_return; + } + + spdlog::info("[node] Starting initial block sync..."); + auto result = co_await sync_from_best_peer(chain_, network_, network_type_); + + if (result.error) { + spdlog::warn("[node] Initial sync failed: {}", result.error.message()); + } else { + spdlog::info("[node] Initial sync complete: {} headers, {} blocks, height {}", + result.headers_received, result.blocks_received, result.final_height); + } + }, ::asio::detached); +#endif - // This is invoked on a new thread. - // This is the end of the derived run startup sequence. - p2p::run(handler); + co_return error::success; } -void full_node::handle_running_chain(code const& ec, result_handler handler) { - if (stopped()) { - handler(error::service_stopped); - return; - } +void full_node::stop() { +#if ! defined(__EMSCRIPTEN__) + network_.stop(); +#endif - if (ec) { - spdlog::error("[node] Failure synchronizing blocks: {}", ec.message()); - handler(ec); - return; + if (!chain_.stop()) { + spdlog::error("[node] Failed to stop blockchain."); } +} - size_t top_height; - hash_digest top_hash; +void full_node::join() { +#if ! defined(__EMSCRIPTEN__) + network_.join(); +#endif - if ( ! chain_.get_last_height(top_height) || - ! chain_.get_block_hash(top_hash, top_height)) { - spdlog::error("[node] The blockchain is corrupt."); - handler(error::operation_failed); - return; + if (!chain_.close()) { + spdlog::error("[node] Failed to close blockchain."); } +} - set_top_block({ std::move(top_hash), top_height }); +bool full_node::stopped() const { +#if ! defined(__EMSCRIPTEN__) + return network_.stopped(); +#else + return true; // In WASM, there's no network, always "stopped" from network perspective +#endif +} - spdlog::info("[node] Node start height is ({}).", top_height); +// ============================================================================= +// Properties +// ============================================================================= - subscribe_blockchain( - std::bind(&full_node::handle_reorganized, this, _1, _2, _3, _4)); +node::settings const& full_node::node_settings() const { + return node_settings_; +} - // This is invoked on a new thread. - // This is the end of the derived run startup sequence. - handler(error::success); +blockchain::settings const& full_node::chain_settings() const { + return chain_settings_; } -// A typical reorganization consists of one incoming and zero outgoing blocks. -bool full_node::handle_reorganized(code ec, size_t fork_height, block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr outgoing) { - if (stopped() || ec == error::service_stopped) { - return false; - } +#if ! defined(__EMSCRIPTEN__) +kth::network::settings const& full_node::network_settings() const { + return network_.network_settings(); +} +#endif - if (ec) { - spdlog::error("[node] Failure handling reorganization: {}", ec.message()); - stop(); - return false; - } +block_chain& full_node::chain() { + return chain_; +} - // Nothing to do here. - if ( ! incoming || incoming->empty()) { - return true; - } +block_chain& full_node::chain_kth() { + return chain_; +} - for (auto const block: *outgoing) { - spdlog::debug("[node] Reorganization moved block to orphan pool [{}]", encode_hash(block->header().hash())); - } +#if ! defined(__EMSCRIPTEN__) +kth::network::p2p_node& full_node::network() { + return network_; +} +#endif - auto const height = *safe_add(fork_height, incoming->size()); +// ============================================================================= +// Thread Pools +// ============================================================================= - set_top_block({ incoming->back()->hash(), height }); - return true; +threadpool& full_node::chain_thread_pool() { + return chain_thread_pool_; } -// Specializations. -// ---------------------------------------------------------------------------- -// Create derived sessions and override these to inject from derived node. - #if ! defined(__EMSCRIPTEN__) -// Must not connect until running, otherwise imports may conflict with sync. -// But we establish the session in network so caller doesn't need to run. -kth::network::session_manual::ptr full_node::attach_manual_session() { - return attach(chain_); +threadpool& full_node::network_thread_pool() { + return network_.thread_pool(); } +#endif + +// ============================================================================= +// Subscriptions +// ============================================================================= -kth::network::session_inbound::ptr full_node::attach_inbound_session() { - return attach(chain_); +full_node::block_channel_ptr full_node::subscribe_blockchain() { + return chain().subscribe_blockchain(); } -kth::network::session_outbound::ptr full_node::attach_outbound_session() { - return attach(chain_); +full_node::transaction_channel_ptr full_node::subscribe_transaction() { + return chain().subscribe_transaction(); } -session_header_sync::ptr full_node::attach_header_sync_session() { - return attach(hashes_, chain_, chain_.chain_settings().checkpoints); +full_node::ds_proof_channel_ptr full_node::subscribe_ds_proof() { + return chain().subscribe_ds_proof(); } -session_block_sync::ptr full_node::attach_block_sync_session() { - return attach(hashes_, chain_, node_settings_); +void full_node::unsubscribe_blockchain(block_channel_ptr const& channel) { + chain().unsubscribe_blockchain(channel); } -#endif -// Shutdown -// ---------------------------------------------------------------------------- +void full_node::unsubscribe_transaction(transaction_channel_ptr const& channel) { + chain().unsubscribe_transaction(channel); +} -bool full_node::stop() { - // Suspend new work last so we can use work to clear subscribers. - auto const p2p_stop = p2p::stop(); - auto const chain_stop = chain_.stop(); +void full_node::unsubscribe_ds_proof(ds_proof_channel_ptr const& channel) { + chain().unsubscribe_ds_proof(channel); +} - if ( ! p2p_stop) { - spdlog::error("[node] Failed to stop network."); - } +// ============================================================================= +// Internal Handlers +// ============================================================================= - if ( ! chain_stop) { - spdlog::error("[node] Failed to stop blockchain."); +bool full_node::handle_reorganized( + code ec, + size_t fork_height, + block_const_ptr_list_const_ptr incoming, + block_const_ptr_list_const_ptr outgoing) +{ + if (stopped() || ec == error::service_stopped) { + return false; } - return p2p_stop && chain_stop; -} - -// This must be called from the thread that constructed this class (see join). -bool full_node::close() { - // Invoke own stop to signal work suspension. - if ( ! full_node::stop()) { + if (ec) { + spdlog::error("[node] Failure handling reorganization: {}", ec.message()); + stop(); return false; } - auto const p2p_close = p2p::close(); - auto const chain_close = chain_.close(); - - if ( ! p2p_close) { - spdlog::error("[node] Failed to close network."); + // Nothing to do here + if (!incoming || incoming->empty()) { + return true; } - if ( ! chain_close) { - spdlog::error("[node] Failed to close blockchain."); + for (auto const& block : *outgoing) { + spdlog::debug("[node] Reorganization moved block to orphan pool [{}]", + encode_hash(block->header().hash())); } - return p2p_close && chain_close; -} - -// Properties. -// ---------------------------------------------------------------------------- - -node::settings const& full_node::node_settings() const { - return node_settings_; -} - -blockchain::settings const& full_node::chain_settings() const { - return chain_settings_; -} - -safe_chain& full_node::chain() { - return chain_; -} - -//TODO: remove this function and use safe_chain in the rpc lib -block_chain& full_node::chain_kth() { - return chain_; -} - -// Subscriptions. -// ---------------------------------------------------------------------------- - -void full_node::subscribe_blockchain(reorganize_handler&& handler) { - chain().subscribe_blockchain(std::move(handler)); -} + auto const height = *safe_add(fork_height, incoming->size()); -void full_node::subscribe_transaction(transaction_handler&& handler) { - chain().subscribe_transaction(std::move(handler)); -} +#if ! defined(__EMSCRIPTEN__) + network_.set_top_block({incoming->back()->hash(), height}); +#endif -void full_node::subscribe_ds_proof(ds_proof_handler&& handler) { - chain().subscribe_ds_proof(std::move(handler)); + return true; } -// Init node utils. -// ------------------------------------------------------------------------ +// ============================================================================= +// Utilities +// ============================================================================= domain::chain::block full_node::get_genesis_block(domain::config::network network) { - switch (network) { case domain::config::network::testnet: return domain::chain::block::genesis_testnet(); @@ -417,235 +353,4 @@ domain::chain::block full_node::get_genesis_block(domain::config::network networ } } -#if defined(KTH_STATISTICS_ENABLED) -#if defined(_WIN32) - -void screen_clear() { - COORD topLeft = { 0, 0 }; - HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO screen; - DWORD written; - - GetConsoleScreenBufferInfo(console, &screen); - FillConsoleOutputCharacterA( - console, ' ', screen.dwSize.X * screen.dwSize.Y, topLeft, &written - ); - FillConsoleOutputAttribute( - console, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE, - screen.dwSize.X * screen.dwSize.Y, topLeft, &written - ); - SetConsoleCursorPosition(console, topLeft); -} - - -#else - -// void screen_clear() { -// // CSI[2J clears screen, CSI[H moves the cursor to top-left corner -// std::print("\x1B[2J\x1B[H"); -// } - -#include -void screen_clear() { - printf("\033c"); -} -#endif - - -//TODO(fernando): could be outside the class -void full_node::print_stat_item_sum(tabulate::Table& stats, size_t from, size_t to, - double accum_transactions, double accum_inputs, double accum_outputs, double accum_wait_total, - double accum_validation_total, double accum_validation_per_input, double accum_deserialization_per_input, - double accum_check_per_input, double accum_population_per_input, double accum_accept_per_input, - double accum_connect_per_input, double accum_deposit_per_input) const { - stats.add_row({ - fmt::format("{}-{}", from, to) - , "Sum" - , fmt::format("{:.0f}", accum_transactions) - , fmt::format("{:.0f}", accum_inputs) - , fmt::format("{:.0f}", accum_outputs) - , fmt::format("{:.0f}", accum_wait_total) - , fmt::format("{:.0f}", accum_validation_total) - , fmt::format("{:.0f}", accum_validation_per_input) - , fmt::format("{:.0f}", accum_deserialization_per_input) - , fmt::format("{:.0f}", accum_check_per_input) - , fmt::format("{:.0f}", accum_population_per_input) - , fmt::format("{:.0f}", accum_accept_per_input) - , fmt::format("{:.0f}", accum_connect_per_input) - , fmt::format("{:.0f}", accum_deposit_per_input)}); - - // last(stats) - // .format() - // .hide_border_top(); -} - -// +---------------+--------+----------------+----------------+--------------+--------------+--------------+--------------+--------------+--------------+------------+------------+-------------+----------------+ -// | Blocks | | Txs | Ins | Outs | Wait(ms) | Val(ms) | Val/In(us) | Deser/In(us) | Check/In(us) | Pop/In(us) | Acc/In(us) | Conn/In(us) | Dep/In(us) | -// | 250000-259999 | Sum | 2908680.000000 | 6443324.000000 | 10000.000000 | 18894.000000 | 32935.000000 | 57795.000000 | 43758.000000 | 12590.000000 | 315.000000 | 108.000000 | 101.000000 | 1315664.000000 | -// | 250000-259999 | Mean | 290.868000 | 644.332400 | 1.000000 | 1.889400 | 3.293500 | 5.779500 | 4.375800 | 1.259000 | 0.031500 | 0.010800 | 0.010100 | 131.566400 | -// | 250000-259999 | Median | 241.962427 | 544.131233 | 1.000000 | 1.572434 | 2.994203 | 5.000129 | 4.000001 | 0.999999 | 0.000000 | 0.000000 | 0.000000 | 103.086477 | -// | 250000-259999 | StDev | 226.992902 | 492.214726 | 0.000000 | 1.409953 | 2.527765 | 6.666403 | 5.388514 | 1.746031 | 0.385127 | 0.148612 | 0.140712 | 440.845418 | -// +---------------+--------+----------------+----------------+--------------+--------------+--------------+--------------+--------------+--------------+------------+------------+-------------+----------------+ - -// Knuth node -// Version -// DB Mode -// Options - -// Synchronizing chain: xxxxx of xxxxx (xx%) - -// Peers - -// Stats - - -//TODO(fernando): could be outside the class -void full_node::print_stat_item(tabulate::Table& stats, size_t from, size_t to, std::string const& cat, - double accum_transactions, double accum_inputs, double accum_outputs, double accum_wait_total, - double accum_validation_total, double accum_validation_per_input, double accum_deserialization_per_input, - double accum_check_per_input, double accum_population_per_input, double accum_accept_per_input, - double accum_connect_per_input, double accum_deposit_per_input) const { - stats.add_row({ - fmt::format("{}-{}", from, to) - , cat - , fmt::format("{:.2f}", accum_transactions) - , fmt::format("{:.2f}", accum_inputs) - , fmt::format("{:.2f}", accum_outputs) - , fmt::format("{:f}", accum_wait_total) - , fmt::format("{:f}", accum_validation_total) - , fmt::format("{:f}", accum_validation_per_input) - , fmt::format("{:f}", accum_deserialization_per_input) - , fmt::format("{:f}", accum_check_per_input) - , fmt::format("{:f}", accum_population_per_input) - , fmt::format("{:f}", accum_accept_per_input) - , fmt::format("{:f}", accum_connect_per_input) - , fmt::format("{:f}", accum_deposit_per_input)}); - - last(stats) - .format() - .hide_border_top(); -} - -void full_node::print_statistics(size_t height) const { - using boost::accumulators::mean; - using boost::accumulators::median; - using boost::accumulators::sum; - - auto from1 = (height / accum_blocks_1_) * accum_blocks_1_; - // auto from2 = (height / accum_blocks_2_) * accum_blocks_2_; - - tabulate::Table stats; - stats.add_row({"Blocks" - ,"" - , "Txs", "Ins", "Outs" - , "Wait(ms)" - , "Val(ms)" - , "Val/In(us)" - , "Deser/In(us)" - , "Check/In(us)" - , "Pop/In(us)" - , "Acc/In(us)" - , "Conn/In(us)" - , "Dep/In(us)"}); - - - // auto formatted = fmt::format("Sum [{}-{}] {:f} txs {:f} ins " - // "{:f} wms {:f} vms {:f} vus {:f} rus {:f} cus {:f} pus " - // "{:f} aus {:f} sus {:f} dus {:f}", - // from1, height, - // boost::accumulators::sum(stats_current1_accum_transactions_), - // boost::accumulators::sum(stats_current1_accum_inputs_), - // boost::accumulators::sum(stats_current1_accum_wait_total_ms_), - // boost::accumulators::sum(stats_current1_accum_validation_total_ms_), - // boost::accumulators::sum(stats_current1_accum_validation_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_deserialization_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_check_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_population_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_accept_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_connect_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_deposit_per_input_us_), - // boost::accumulators::sum(stats_current1_accum_cache_efficiency_)); - - // spdlog::info("[blockchain] ************************************************************************************************************************"); - // spdlog::info("[blockchain] Stats:"); - // spdlog::info("[blockchain] {}", formatted); - - print_stat_item_sum(stats, from1, height, - sum(stats_current1_accum_transactions_), - sum(stats_current1_accum_inputs_), - sum(stats_current1_accum_outputs_), - sum(stats_current1_accum_wait_total_ms_), - sum(stats_current1_accum_validation_total_ms_), - sum(stats_current1_accum_validation_per_input_us_), - sum(stats_current1_accum_deserialization_per_input_us_), - sum(stats_current1_accum_check_per_input_us_), - sum(stats_current1_accum_population_per_input_us_), - sum(stats_current1_accum_accept_per_input_us_), - sum(stats_current1_accum_connect_per_input_us_), - sum(stats_current1_accum_deposit_per_input_us_)); - - print_stat_item(stats, from1, height, "Mean", - mean(stats_current1_accum_transactions_), - mean(stats_current1_accum_inputs_), - mean(stats_current1_accum_outputs_), - mean(stats_current1_accum_wait_total_ms_), - mean(stats_current1_accum_validation_total_ms_), - mean(stats_current1_accum_validation_per_input_us_), - mean(stats_current1_accum_deserialization_per_input_us_), - mean(stats_current1_accum_check_per_input_us_), - mean(stats_current1_accum_population_per_input_us_), - mean(stats_current1_accum_accept_per_input_us_), - mean(stats_current1_accum_connect_per_input_us_), - mean(stats_current1_accum_deposit_per_input_us_)); - - print_stat_item(stats, from1, height, "Median", - median(stats_current1_accum_transactions_), - median(stats_current1_accum_inputs_), - median(stats_current1_accum_outputs_), - median(stats_current1_accum_wait_total_ms_), - median(stats_current1_accum_validation_total_ms_), - median(stats_current1_accum_validation_per_input_us_), - median(stats_current1_accum_deserialization_per_input_us_), - median(stats_current1_accum_check_per_input_us_), - median(stats_current1_accum_population_per_input_us_), - median(stats_current1_accum_accept_per_input_us_), - median(stats_current1_accum_connect_per_input_us_), - median(stats_current1_accum_deposit_per_input_us_)); - - stdev_sample stdev; - print_stat_item(stats, from1, height, "StDev", - stdev(stats_current1_accum_transactions_), - stdev(stats_current1_accum_inputs_), - stdev(stats_current1_accum_outputs_), - stdev(stats_current1_accum_wait_total_ms_), - stdev(stats_current1_accum_validation_total_ms_), - stdev(stats_current1_accum_validation_per_input_us_), - stdev(stats_current1_accum_deserialization_per_input_us_), - stdev(stats_current1_accum_check_per_input_us_), - stdev(stats_current1_accum_population_per_input_us_), - stdev(stats_current1_accum_accept_per_input_us_), - stdev(stats_current1_accum_connect_per_input_us_), - stdev(stats_current1_accum_deposit_per_input_us_)); - - - for (size_t i = 2; i < 14; ++i) { - stats.column(i).format().font_align(tabulate::FontAlign::right); - } - - for (size_t i = 0; i < 14; ++i) { - stats[0][i].format() - .font_color(tabulate::Color::yellow) - .font_align(tabulate::FontAlign::center) - .font_style({tabulate::FontStyle::bold}); - } - - screen_clear(); - std::print("{}\n\n", stats.str()); - - // spdlog::info("[blockchain] ************************************************************************************************************************"); -} - -#endif - - -} // namespace kth::node \ No newline at end of file +} // namespace kth::node diff --git a/src/node/src/parser.cpp b/src/node/src/parser.cpp index 2aa981d1..70f250f8 100644 --- a/src/node/src/parser.cpp +++ b/src/node/src/parser.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace kth::domain::config { @@ -50,6 +51,26 @@ void validate(boost::any& v, std::vector const& values, network* ta } // namespace kth::domain::config +namespace kth { + +void validate(boost::any& v, std::vector const& values, display_mode* /*target_type*/, int) { + using namespace boost::program_options; + + validators::check_first_occurrence(v); + auto const& s = validators::get_single_string(values); + + if (s == "tui" || s == "TUI") { + v = boost::any(display_mode::tui); + } else if (s == "log" || s == "LOG") { + v = boost::any(display_mode::log); + } else if (s == "daemon" || s == "DAEMON") { + v = boost::any(display_mode::daemon); + } else { + throw validation_error(validation_error::invalid_option_value); + } +} + +} // namespace kth // TODO: localize descriptions. namespace kth::node { @@ -136,6 +157,11 @@ options_metadata parser::load_options() { value(&configured.version)-> default_value(false)->zero_tokens(), "Display version information." + )( + "display,d", + value(&configured.node.display)-> + default_value(kth::display_mode::log, "log"), + "Display mode (tui, log, daemon). Default: log." ); return description; @@ -563,6 +589,10 @@ options_metadata parser::load_settings() { "node.ds_proofs", value(&configured.node.ds_proofs_enabled), "Double-Spend Proofs, default to false." + )( + "node.display", + value(&configured.node.display), + "Display mode (tui, log, daemon). Default: log." ) #if defined(KTH_WITH_MEMPOOL) diff --git a/src/node/src/protocols/protocol_block_in.cpp b/src/node/src/protocols/protocol_block_in.cpp deleted file mode 100644 index 66c5f34b..00000000 --- a/src/node/src/protocols/protocol_block_in.cpp +++ /dev/null @@ -1,819 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -//Note(fernando): to force a debugger breakpoint we can use -// asm("int $3"); - -#define FMT_HEADER_ONLY 1 -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -#define NAME "block_in" -#define CLASS protocol_block_in - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::chrono; -using namespace std::placeholders; - -constexpr -uint64_t get_compact_blocks_version() { -#if defined(KTH_CURRENCY_BCH) - return 1; -#else - return 2; -#endif -} - -protocol_block_in::protocol_block_in(full_node& node, channel::ptr channel, safe_chain& chain) - : protocol_timer(node, channel, false, NAME), - node_(node), - chain_(chain), - block_latency_(node.node_settings().block_latency()), - - // TODO: move send_headers to a derived class protocol_block_in_70012. - headers_from_peer_(negotiated_version() >= version::level::bip130), - - // TODO: move send_compact to a derived class protocol_block_in_70014. - compact_from_peer_(negotiated_version() >= version::level::bip152), - - compact_blocks_high_bandwidth_set_(false), - - // This patch is treated as integral to basic block handling. - blocks_from_peer_( - negotiated_version() > version::level::no_blocks_end || - negotiated_version() < version::level::no_blocks_start), - - CONSTRUCT_TRACK(protocol_block_in) -{} - -// Start. -//----------------------------------------------------------------------------- - -void protocol_block_in::start() { - // Use timer to drop slow peers. - protocol_timer::start(block_latency_, BIND1(handle_timeout, _1)); - - // TODO: move headers to a derived class protocol_block_in_31800. - SUBSCRIBE2(headers, handle_receive_headers, _1, _2); - - // TODO: move not_found to a derived class protocol_block_in_70001. - SUBSCRIBE2(not_found, handle_receive_not_found, _1, _2); - SUBSCRIBE2(inventory, handle_receive_inventory, _1, _2); - SUBSCRIBE2(block, handle_receive_block, _1, _2); - - SUBSCRIBE2(compact_block, handle_receive_compact_block, _1, _2); - SUBSCRIBE2(block_transactions, handle_receive_block_transactions, _1, _2); - - // TODO: move send_headers to a derived class protocol_block_in_70012. - if (headers_from_peer_) { - // Ask peer to send headers vs. inventory block announcements. - SEND2(send_headers{}, handle_send, _1, send_headers::command); - } - - // TODO: move send_compact to a derived class protocol_block_in_70014. - if (compact_from_peer_) { - if (chain_.is_stale()) { - //force low bandwidth - spdlog::debug("[node] The chain is stale, send sendcmcpt low bandwidth [{}]", authority()); - SEND2((send_compact{false, get_compact_blocks_version()}), handle_send, _1, send_compact::command); - } else { - spdlog::debug("[node] The chain is not stale, send sendcmcpt with configured setting [{}]", authority()); - SEND2((send_compact{node_.node_settings().compact_blocks_high_bandwidth, get_compact_blocks_version()}), handle_send, _1, send_compact::command); - compact_blocks_high_bandwidth_set_ = node_.node_settings().compact_blocks_high_bandwidth; - } - } - - send_get_blocks(null_hash); -} - -// Send get_[headers|blocks] sequence. -//----------------------------------------------------------------------------- - -void protocol_block_in::send_get_blocks(hash_digest const& stop_hash) { - auto const heights = block::locator_heights(node_.top_block().height()); - chain_.fetch_block_locator(heights, BIND3(handle_fetch_block_locator, _1, _2, stop_hash)); -} - -void protocol_block_in::handle_fetch_block_locator(code const& ec, get_headers_ptr message, hash_digest const& stop_hash) { - if (stopped(ec)) { - return; - } - - if (ec) { - spdlog::error("[node] Internal failure generating block locator for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - if (message->start_hashes().empty()) { - return; - } - - auto const& last_hash = message->start_hashes().front(); - - // TODO: move get_headers to a derived class protocol_block_in_31800. - auto const use_headers = negotiated_version() >= version::level::headers; - auto const request_type = (use_headers ? "headers" : "inventory"); - - if (stop_hash == null_hash) { - spdlog::debug("[node] Ask [{}] for {} after [{}]", authority(), request_type, encode_hash(last_hash)); - } else { - spdlog::debug("[node] Ask [{}] for {} from [{}] through [{}]", authority(), request_type, encode_hash(last_hash), encode_hash(stop_hash)); - } - - message->set_stop_hash(stop_hash); - - if (use_headers) { - SEND2(*message, handle_send, _1, message->command); - } else { - SEND2(static_cast(*message), handle_send, _1, message->command); - } -} - -// Receive headers|inventory sequence. -//----------------------------------------------------------------------------- - -// TODO: move headers to a derived class protocol_block_in_31800. -// This originates from send_header->annoucements and get_headers requests, or -// from an unsolicited announcement. There is no way to distinguish. -bool protocol_block_in::handle_receive_headers(code const& ec, headers_const_ptr message) { - if (stopped(ec)) { - return false; - } - - // We don't want to request a batch of headers out of order. - if ( ! message->is_sequential()) { - spdlog::warn("[node] Block headers out of order from [{}].", authority()); - stop(error::channel_stopped); - return false; - } - - // There is no benefit to this use of headers, in fact it is suboptimal. - // In v3 headers will be used to build block tree before getting blocks. - auto const response = std::make_shared(); - - if (compact_from_peer_) { - message->to_inventory(response->inventories(), inventory::type_id::compact_block); - } else { - message->to_inventory(response->inventories(), inventory::type_id::block); - } - - // Remove hashes of blocks that we already have. - chain_.filter_blocks(response, BIND2(send_get_data, _1, response)); - return true; -} - -// This originates from default annoucements and get_blocks requests, or from -// an unsolicited announcement. There is no way to distinguish. -bool protocol_block_in::handle_receive_inventory(code const& ec, inventory_const_ptr message) { - if (stopped(ec)) { - return false; - } - - auto const response = std::make_shared(); - - if (compact_from_peer_) { - message->reduce(response->inventories(), inventory::type_id::compact_block); - } else { - message->reduce(response->inventories(), inventory::type_id::block); - } - - // Remove hashes of blocks that we already have. - chain_.filter_blocks(response, BIND2(send_get_data, _1, response)); - return true; -} - -void protocol_block_in::send_get_data(code const& ec, get_data_ptr message) { - if (stopped(ec)) { - return; - } - - if (ec) { - spdlog::error("[node] Internal failure filtering block hashes for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - if (message->inventories().empty()) { - return; - } - - if (compact_from_peer_) { - if (node_.node_settings().compact_blocks_high_bandwidth) { - if ( ! compact_blocks_high_bandwidth_set_ && ! chain_.is_stale() ) { - spdlog::info("[node] The chain is not stale, send sendcmcpt with high bandwidth [{}]", authority()); - SEND2((send_compact{true, get_compact_blocks_version()}), handle_send, _1, send_compact::command); - compact_blocks_high_bandwidth_set_ = true; - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // Critical Section - mutex.lock_upgrade(); - auto const fresh = backlog_.empty(); - mutex.unlock_upgrade_and_lock(); - //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - // Enqueue the block inventory behind the preceding block inventory. - for (auto const& inventory: message->inventories()){ - if (inventory.type() == inventory::type_id::block) { - backlog_.push(inventory.hash()); - } else if (inventory.type() == inventory::type_id::compact_block) { - backlog_.push(inventory.hash()); - } - } - - mutex.unlock(); - /////////////////////////////////////////////////////////////////////////// - - // There was no backlog so the timer must be started now. - if (fresh) { - reset_timer(); - } - - // inventory|headers->get_data[blocks] - SEND2(*message, handle_send, _1, message->command); -} - -// Receive not_found sequence. -//----------------------------------------------------------------------------- - -// TODO: move not_found to a derived class protocol_block_in_70001. -bool protocol_block_in::handle_receive_not_found(code const& ec, not_found_const_ptr message) { - if (stopped(ec)) { - return false; - } - - if (ec) { - spdlog::debug("[node] Failure getting block not_found from [{}] {}", authority(), ec.message()); - stop(ec); - return false; - } - - hash_list hashes; - message->to_hashes(hashes, inventory::type_id::block); - - for (auto const& hash : hashes) { - spdlog::debug("[node] Block not_found [{}] from [{}]", encode_hash(hash), authority()); - } - - // The peer cannot locate one or more blocks that it told us it had. - // This only results from reorganization assuming peer is proper. - // Drop the peer so next channgel generates a new locator and backlog. - if ( ! hashes.empty()) { - stop(error::channel_stopped); - } - - return true; -} - -// Receive block sequence. -//----------------------------------------------------------------------------- - -void protocol_block_in::organize_block(block_const_ptr message) { - message->validation.originator = nonce(); - chain_.organize(message, BIND2(handle_store_block, _1, message)); -} - -bool protocol_block_in::handle_receive_block(code const& ec, block_const_ptr message) { - if (stopped(ec)) { - return false; - } - - /////////////////////////////////////////////////////////////////////////// - // Critical Section - mutex.lock(); - - auto matched = ! backlog_.empty() && backlog_.front() == message->hash(); - - if (matched) { - backlog_.pop(); - } - - // Empty after pop means we need to make a new request. - auto const cleared = backlog_.empty(); - - mutex.unlock(); - /////////////////////////////////////////////////////////////////////////// - - // If a peer sends a block unannounced we drop the peer - always. However - // it is common for block announcements to cause block requests to be sent - // out of backlog order due to interleaving of threads. This results in - // channel drops during initial block download but not after sync. The - // resolution to this issue is use of headers-first sync, but short of that - // the current implementation performs well and drops peers no more - // frequently than block announcements occur during initial block download, - // and not typically after it is complete. - if ( ! matched) { - spdlog::debug("[node] Block [{}] unexpected or out of order from [{}]", encode_hash(message->hash()), authority()); - stop(error::channel_stopped); - return false; - } - - // message->validation.originator = nonce(); - // chain_.organize(message, BIND2(handle_store_block, _1, message)); - organize_block(message); - - // Sending a new request will reset the timer upon inventory->get_data, but - // we need to time out the lack of response to those requests when stale. - // So we rest the timer in case of cleared and for not cleared. - reset_timer(); - - if (cleared) { - send_get_blocks(null_hash); - } - - return true; -} - -bool protocol_block_in::handle_receive_block_transactions(code const& ec, block_transactions_const_ptr message) { - if (stopped(ec)) { - return false; - } - - auto it = compact_blocks_map_.find(message->block_hash()); - if (it == compact_blocks_map_.end()) { - spdlog::debug("[node] Compact Block [{}] The blocktxn received doesn't match with any temporal compact block [{}]", encode_hash(message->block_hash()), authority()); - stop(error::channel_stopped); - return false; - } - - auto temp_compact_block_ = it->second; - - auto const& vtx_missing = message->transactions(); - - auto& txn_available = temp_compact_block_.transactions; - auto const& header_temp = temp_compact_block_.header; - - size_t tx_missing_offset = 0; - - for (size_t i = 0; i < txn_available.size(); i++) { - if ( ! txn_available[i].is_valid()) { - if (vtx_missing.size() <= tx_missing_offset) { - spdlog::debug("[node] Compact Block [{}] The offset {} is invalid [{}]", encode_hash(message->block_hash()), tx_missing_offset, authority()); - stop(error::channel_stopped); - - //TODO(Mario) verify if necesary mutual exclusion - compact_blocks_map_.erase(it); - return false; - } - txn_available[i] = std::move(vtx_missing[tx_missing_offset]); - ++tx_missing_offset; - } - } - - if (vtx_missing.size() != tx_missing_offset) { - spdlog::debug("[node] Compact Block [{}] The offset {} is invalid [{}]", encode_hash(message->block_hash()), tx_missing_offset, authority()); - stop(error::channel_stopped); - - //TODO(Mario): verify if necesary mutual exclusion - compact_blocks_map_.erase(it); - return false; - } - - auto const tempblock = std::make_shared(std::move(header_temp), std::move(txn_available)); - organize_block(tempblock); - //TODO(Mario) verify if necesary mutual exclusion - compact_blocks_map_.erase(it); - - return true; -} - -void protocol_block_in::handle_fetch_block_locator_compact_block(code const& ec, get_headers_ptr message, hash_digest const& stop_hash) { - if (stopped(ec)) { - return; - } - - if (ec) { - spdlog::error("[node] Internal failure generating block locator (compact block) for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - if (message->start_hashes().empty()) { - return; - } - - message->set_stop_hash(stop_hash); - SEND2(*message, handle_send, _1, message->command); - - spdlog::debug("[node] Sended get header message compact blocks to [{}]", authority()); - -} - -bool protocol_block_in::handle_receive_compact_block(code const& ec, compact_block_const_ptr message) { - if (stopped(ec)) { - return false; - } - - //TODO(Mario): purge old compact blocks - - //the header of the compact block is the header of the block - auto const& header_temp = message->header(); - - if ( ! header_temp.is_valid()) { - spdlog::debug("[node] Compact Block [{}] The compact block header is invalid [{}]", encode_hash(header_temp.hash()), authority()); - stop(error::channel_stopped); - return false; - } - - //if the compact block exists in the map, is already in process - if (compact_blocks_map_.count(header_temp.hash()) > 0) { - return true; - } - - //if we haven't the parent block already, send a get_header message and return - if ( ! chain_.get_block_exists_safe(header_temp.previous_block_hash() ) ) { - spdlog::debug("[node] Compact Block parent block not exists [ {} [{}]", encode_hash(header_temp.previous_block_hash()), authority()); - - if ( ! chain_.is_stale() ) { - spdlog::debug("[node] The chain isn't stale sending getheaders message [{}]", authority()); - auto const heights = block::locator_heights(node_.top_block().height()); - chain_.fetch_block_locator(heights,BIND3(handle_fetch_block_locator_compact_block, _1, _2, null_hash)); - } - return true; - } - // else { - // spdlog::info("[node] - //] Compact Block parent block EXISTS [ {} [{}]", encode_hash(header_temp.previous_block_hash()) - //, authority()); - // } - - - //the nonce used to calculate the short id - auto const nonce = message->nonce(); - auto const& prefiled_txs = message->transactions(); - auto const& short_ids = message->short_ids(); - - std::vector txs_available(short_ids.size() + prefiled_txs.size()); - int32_t lastprefilledindex = -1; - - for (size_t i = 0; i < prefiled_txs.size(); ++i) { - if ( ! prefiled_txs[i].is_valid()) { - - spdlog::debug("[node] Compact Block [{}] The prefilled transaction is invalid [{}]", encode_hash(header_temp.hash()), authority()); - stop(error::channel_stopped); - return false; - } - - //encoded = (current_index - prev_index) - 1 - // current = +1 + prev - // prev current - lastprefilledindex += prefiled_txs[i].index() + 1; - - - if (lastprefilledindex > std::numeric_limits::max()) { - spdlog::debug("[node] Compact Block [{}] The prefilled index {} is out of range [{}]", encode_hash(header_temp.hash()), lastprefilledindex, authority()); - stop(error::channel_stopped); - return false; - } - - if ((uint32_t)lastprefilledindex > short_ids.size() + i) { - // If we are inserting a tx at an index greater than our full list - // of shorttxids plus the number of prefilled txn we've inserted, - // then we have txn for which we have neither a prefilled txn or a - // shorttxid! - - spdlog::debug("[node] Compact Block [{}] The prefilled index {} is out of range [{}]", encode_hash(header_temp.hash()), lastprefilledindex, authority()); - stop(error::channel_stopped); - return false; - } - - txs_available[lastprefilledindex] = prefiled_txs[i].transaction(); - } - - // Calculate map of txids -> positions and check mempool to see what we have - // (or don't). Because well-formed cmpctblock messages will have a - // (relatively) uniform distribution of short IDs, any highly-uneven - // distribution of elements can be safely treated as a READ_STATUS_FAILED. - std::unordered_map shorttxids(short_ids.size()); - uint16_t index_offset = 0; - - for (size_t i = 0; i < short_ids.size(); ++i) { - - while (txs_available[i + index_offset].is_valid()) { - ++index_offset; - } - shorttxids[short_ids[i]] = i + index_offset; - // To determine the chance that the number of entries in a bucket - // exceeds N, we use the fact that the number of elements in a single - // bucket is binomially distributed (with n = the number of shorttxids - // S, and p = 1 / the number of buckets), that in the worst case the - // number of buckets is equal to S (due to std::unordered_map having a - // default load factor of 1.0), and that the chance for any bucket to - // exceed N elements is at most buckets * (the chance that any given - // bucket is above N elements). Thus: P(max_elements_per_bucket > N) <= - // S * (1 - cdf(binomial(n=S,p=1/S), N)). If we assume blocks of up to - // 16000, allowing 12 elements per bucket should only fail once per ~1 - // million block transfers (per peer and connection). - - if (shorttxids.bucket_size(shorttxids.bucket(short_ids[i])) > 12) { - // Duplicate txindexes, the block is now in-flight, so - // just request it. - - spdlog::info("[node] Compact Block, sendening getdata for hash ({}) to [{}]", encode_hash(header_temp.hash()), authority()); - send_get_data_compact_block(ec, header_temp.hash()); - - return true; - } - } - - - // TODO: in the shortid-collision case, we should instead request both - // transactions which collided. Falling back to full-block-request here is - // overkill. - if (shorttxids.size() != short_ids.size()) { - // Short ID collision - spdlog::info("[node] Compact Block, sendening getdata for hash ({}) to [{}]", encode_hash(header_temp.hash()), authority()); - send_get_data_compact_block(ec, header_temp.hash()); - return true; - } - - size_t mempool_count = 0; - chain_.fill_tx_list_from_mempool(*message, mempool_count, txs_available, shorttxids); - - std::vector txs; - size_t prev_idx = 0; - - for (size_t i = 0; i < txs_available.size(); ++i) { - if ( ! txs_available[i].is_valid()) { - //diff_enc = (current_index - prev_index) - 1 - size_t diff_enc = i - prev_idx - (txs.size() > 0 ? 1 : 0); - prev_idx = i; - txs.push_back(diff_enc); - } - } - - if (txs.empty()) { - auto const tempblock = std::make_shared(std::move(header_temp), std::move(txs_available)); - organize_block(tempblock); - return true; - } else { - compact_blocks_map_.emplace(header_temp.hash(), temp_compact_block{std::move(header_temp), std::move(txs_available)}); - auto req_tx = get_block_transactions(header_temp.hash(),txs); - SEND2(req_tx, handle_send, _1, get_block_transactions::command); - return true; - } -} - -void protocol_block_in::send_get_data_compact_block(code const& ec, hash_digest const& hash) { - hash_list hashes; - hashes.push_back(hash); - - get_data_ptr request; - request = std::make_shared(hashes, inventory::type_id::block); - - send_get_data(ec,request); -} - -// The block has been saved to the block chain (or not). -// This will be picked up by subscription in block_out and will cause the block -// to be announced to non-originating peers. -void protocol_block_in::handle_store_block(code const& ec, block_const_ptr message) { - if (stopped(ec)) { - return; - } - - auto const hash = message->header().hash(); - - // Ask the peer for blocks from the chain top up to this orphan. - if (ec == error::orphan_block) { - send_get_blocks(hash); - } - - auto const encoded = encode_hash(hash); - - if (ec == error::orphan_block || - ec == error::duplicate_block || - ec == error::insufficient_work) { - spdlog::debug("[node] Captured block [{}] from [{}] {}", encoded, authority(), ec.message()); - return; - } - - // TODO: send reject as applicable. - if (ec) { - spdlog::debug("[node] Rejected block [{}] from [{}] {}", encoded, authority(), ec.message()); - stop(ec); - return; - } - - auto const state = message->validation.state; - KTH_ASSERT(state); - - // Show that diplayed forks may be missing activations due to checkpoints. - auto const checked = state->is_under_checkpoint() ? "*" : ""; - - spdlog::debug("[node] Connected block [{}] at height [{}] from [{}] ({}{}, {}).", encoded, state->height(), authority(), state->enabled_forks(), checked, state->minimum_version()); - - -#if defined(KTH_STATISTICS_ENABLED) - report(*message, node_); -#else - report(*message); -#endif -} - -// Subscription. -//----------------------------------------------------------------------------- - -// This is fired by the callback (i.e. base timer and stop handler). -void protocol_block_in::handle_timeout(code const& ec) { - if (stopped(ec)) { - // This may get called more than once per stop. - handle_stop(ec); - return; - } - - // Since we need blocks do not stay connected to peer in bad version range. - if ( ! blocks_from_peer_) { - stop(error::channel_stopped); - return; - } - - if (ec && ec != error::channel_timeout) { - spdlog::debug("[node] Failure in block timer for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - /////////////////////////////////////////////////////////////////////////// - // Critical Section - mutex.lock_shared(); - auto const backlog_empty = backlog_.empty(); - mutex.unlock_shared(); - /////////////////////////////////////////////////////////////////////////// - - // Can only end up here if time was not extended. - if ( ! backlog_empty) { - spdlog::debug("[node] Peer [{}] exceeded configured block latency.", authority()); - stop(ec); - } - - // Can only end up here if peer did not respond to inventory or get_data. - // At this point we are caught up with an honest peer. But if we are stale - // we should try another peer and not just keep pounding this one. - if (chain_.is_stale()) { - stop(error::channel_stopped); - } - - // If we are not stale then we are either good or stalled until peer sends - // an announcement. There is no sense pinging a broken peer, so we either - // drop the peer after a certain mount of time (above 10 minutes) or rely - // on other peers to keep us moving and periodically age out connections. - // Note that this allows a non-witness peer to hang on indefinately to our - // witness-requiring node until the node becomes stale. Allowing this then - // depends on requiring witness peers for explicitly outbound connections. -} - -void protocol_block_in::handle_stop(code const&) { - spdlog::debug("[network] Stopped block_in protocol for [{}].", authority()); -} - -// Block reporting. -//----------------------------------------------------------------------------- - -inline -bool enabled(size_t height) { - // Vary the reporting performance reporting interval by height. - // auto const modulus = - // (height < 100000 ? 100 : - // (height < 200000 ? 10 : 1)); - - // return height % modulus == 0; - - return true; -} - -inline -float difference(const asio::time_point& start, const asio::time_point& end) { - auto const elapsed = duration_cast(end - start); - return float(elapsed.count()); -} - -inline -size_t unit_cost(const asio::time_point& start, const asio::time_point& end, size_t value) { - return size_t(std::round(difference(start, end) / value)); -} - -inline -size_t total_cost_ms(const asio::time_point& start, const asio::time_point& end) { - static constexpr size_t microseconds_per_millisecond = 1000; - return unit_cost(start, end, microseconds_per_millisecond); -} - -//static - -#if defined(KTH_STATISTICS_ENABLED) -void protocol_block_in::report(domain::chain::block const& block, full_node& node) { -#else -void protocol_block_in::report(domain::chain::block const& block) { -#endif - KTH_ASSERT(block.validation.state); - auto const height = block.validation.state->height(); - -#if defined(KTH_STATISTICS_ENABLED) - if (true) { -#else - if (enabled(height)) { -#endif - auto const& times = block.validation; - auto const now = asio::steady_clock::now(); - auto const transactions = block.transactions().size(); - auto const inputs = std::max(block.total_inputs(), size_t(1)); - auto const outputs = size_t{1}; - - // // auto const outputs = std::max(block.total_outputs(), size_t(1)); - // // auto [inputs, outputs] = block.total_inputs_outputs(); - // auto [inputs, outputs] = domain::chain::total_inputs_outputs(block); - - // inputs = std::max(inputs, size_t(1)); - // outputs = std::max(outputs, size_t(1)); - - // Subtract total deserialization time from start of validation because - // the wait time is between end_deserialize and start_check. This lets - // us simulate block announcement validation time as there is no wait. - auto const start_validate = times.start_check - (times.end_deserialize - times.start_deserialize); - -#if defined(KTH_STATISTICS_ENABLED) - node.collect_statistics(height, transactions, inputs, outputs, - total_cost_ms(times.end_deserialize, times.start_check), - total_cost_ms(start_validate, times.start_notify), - unit_cost(start_validate, times.start_notify, inputs), - unit_cost(times.start_deserialize, times.end_deserialize, inputs), - unit_cost(times.start_check, times.start_populate, inputs), - unit_cost(times.start_populate, times.start_accept, inputs), - unit_cost(times.start_accept, times.start_connect, inputs), - unit_cost(times.start_connect, times.start_notify, inputs), - unit_cost(times.start_push, times.end_push, inputs), - block.validation.cache_efficiency); -#endif - - auto formatted = fmt::format("[{:6}] {:>5} txs {:>5} ins " - "{:>4} wms {:>5} vms {:>4} vus {:>4} rus {:>4} cus {:>4} pus " - "{:>4} aus {:>4} sus {:>4} dus {:f}", height, transactions, inputs, - - // wms: wait total (ms) - total_cost_ms(times.end_deserialize, times.start_check), - - // vms: validation total (ms) - total_cost_ms(start_validate, times.start_notify), - - // vus: validation per input (µs) - unit_cost(start_validate, times.start_notify, inputs), - - // rus: deserialization (read) per input (µs) - unit_cost(times.start_deserialize, times.end_deserialize, inputs), - - // cus: check per input (µs) - unit_cost(times.start_check, times.start_populate, inputs), - - // pus: population per input (µs) - unit_cost(times.start_populate, times.start_accept, inputs), - - // aus: accept per input (µs) - unit_cost(times.start_accept, times.start_connect, inputs), - - // sus: connect (script) per input (µs) - unit_cost(times.start_connect, times.start_notify, inputs), - - // dus: deposit per input (µs) - unit_cost(times.start_push, times.end_push, inputs), - - // this block transaction cache efficiency (hits/queries) - block.validation.cache_efficiency); - -#if defined(KTH_STATISTICS_ENABLED) - if (enabled(height)) { - spdlog::debug("[blockchain] {}", formatted); - } -#else - // spdlog::info("[blockchain] {}", formatted); - spdlog::info("{}", formatted); -#endif - } -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_block_out.cpp b/src/node/src/protocols/protocol_block_out.cpp deleted file mode 100644 index 5091204e..00000000 --- a/src/node/src/protocols/protocol_block_out.cpp +++ /dev/null @@ -1,544 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -#include - -namespace kth::node { - -#define NAME "block_out" -#define CLASS protocol_block_out - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace boost::adaptors; -using namespace std::placeholders; - -protocol_block_out::protocol_block_out(full_node& node, channel::ptr channel, safe_chain& chain) - : protocol_events(node, channel, NAME), - node_(node), - last_locator_top_(null_hash), - chain_(chain), - - // TODO: move send_compact to a derived class protocol_block_out_70014. - compact_to_peer_(false), - compact_high_bandwidth_(true), -#if defined(KTH_CURRENCY_BCH) - compact_version_(1), -#else - compact_version_(2), -#endif - // TODO: move send_headers to a derived class protocol_block_out_70012. - headers_to_peer_(false), - - CONSTRUCT_TRACK(protocol_block_out) -{} - -// Start. -//----------------------------------------------------------------------------- - -void protocol_block_out::start() { - protocol_events::start(BIND1(handle_stop, _1)); - - // TODO: Do not enable bip152 protocol level until fully-implemented. - // TODO: move send_compact to a derived class protocol_block_out_70014. - if (negotiated_version() >= version::level::bip152) { - // Announce compact vs. header/inventory if compact_to_peer_ is set. - SUBSCRIBE2(send_compact, handle_receive_send_compact, _1, _2); - } - - // TODO: move send_headers to a derived class protocol_block_out_70012. - if (negotiated_version() >= version::level::bip130) { - // Announce headers vs. inventory if headers_to_peer_ is set. - SUBSCRIBE2(send_headers, handle_receive_send_headers, _1, _2); - } - - // TODO: move get_headers to a derived class protocol_block_out_31800. - SUBSCRIBE2(get_headers, handle_receive_get_headers, _1, _2); - SUBSCRIBE2(get_blocks, handle_receive_get_blocks, _1, _2); - SUBSCRIBE2(get_data, handle_receive_get_data, _1, _2); - - SUBSCRIBE2(get_block_transactions, handle_receive_get_block_transactions, _1, _2); - - // Subscribe to block acceptance notifications (the block-out heartbeat). - chain_.subscribe_blockchain(BIND4(handle_reorganized, _1, _2, _3, _4)); -} - -// Receive send_headers and send_compact. -//----------------------------------------------------------------------------- - -// TODO: move send_compact to a derived class protocol_block_out_70014. -bool protocol_block_out::handle_receive_send_compact(code const& ec, send_compact_const_ptr message) { - if (stopped(ec)) { - return false; - } - - compact_to_peer_ = true; - compact_high_bandwidth_ = message->high_bandwidth_mode(); - compact_version_ = message->version(); - return false; -} - -// TODO: move send_headers to a derived class protocol_block_out_70012. -bool protocol_block_out::handle_receive_send_headers(code const& ec, send_headers_const_ptr message) { - if (stopped(ec)) { - return false; - } - - // Block annoucements will be headers messages instead of inventory. - headers_to_peer_ = true; - return false; -} - -// Receive get_headers sequence. -//----------------------------------------------------------------------------- - -// TODO: move get_headers to a derived class protocol_block_out_31800. -bool protocol_block_out::handle_receive_get_headers(code const& ec, get_headers_const_ptr message) { - if (stopped(ec)) { - return false; - } - - auto const size = message->start_hashes().size(); - - if (size > max_locator) { - spdlog::warn("[node] Excessive get_headers locator size ({}) from [{}]", size, authority()); - stop(error::channel_stopped); - return false; - } - - if (size > locator_limit()) { - spdlog::debug("[node] Disallowed get_headers locator size ({}) from [{}]", size, authority()); - return true; - } - - auto const threshold = last_locator_top_.load(); - chain_.fetch_locator_block_headers(message, threshold, max_get_headers, BIND2(handle_fetch_locator_headers, _1, _2)); - return true; -} - -// TODO: move headers to a derived class protocol_block_out_31800. -void protocol_block_out::handle_fetch_locator_headers(code const& ec, headers_ptr message) { - if (stopped(ec)) { - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating locator block headers for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - //Note(kth): In case message-> elements() is empty, the headers message also needs - // to return an empty array, so the getheaders sender knows that it is already synced. - // Respond to get_headers with headers. - SEND2(*message, handle_send, _1, message->command); - - if (message->elements().empty()) { - return; - } - - // Allow a peer to sync despite our being stale. - ////if (chain_.is_stale()) - //// return; - - // Save the locator top to limit an overlapping future request. - last_locator_top_.store(message->elements().front().hash()); -} - -bool protocol_block_out::handle_receive_get_block_transactions(code const& ec, get_block_transactions_const_ptr message) { - if (stopped(ec)) - return false; - - auto block_hash = message->block_hash(); - - chain_.fetch_block(block_hash, [this, message](code const& ec, block_const_ptr block, uint64_t) { - - if (ec == error::success) { - - auto indexes = message->indexes(); - - //TODO(Mario) - /*if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) { - // If an older block is requested (should never happen in practice, - // but can happen in tests) send a block response instead of a - // blocktxn response. Sending a full block response instead of a - // small blocktxn response is preferable in the case where a peer - // might maliciously send lots of getblocktxn requests to trigger - // expensive disk reads, because it will require the peer to - // actually receive all the data read from disk over the network. - }*/ - - uint16_t offset = 0; - for (size_t j = 0; j < indexes.size(); j++) { - if (uint64_t(message->indexes()[j]) + uint64_t(offset) > std::numeric_limits::max()) { - spdlog::warn("[node] Compact Blocks index offset is invalid from [{}]", authority()); - stop(error::channel_stopped); - return; - } - - indexes[j] = indexes[j] + offset; - offset = indexes[j] + 1; - } - - domain::chain::transaction::list txs_list(indexes.size()); - - for (size_t i = 0; i < indexes.size(); i++) { - if (indexes[i] >= block->transactions().size()) { - spdlog::warn("[node] Compact Blocks index is greater than transactions size from [{}]", authority()); - stop(error::channel_stopped); - return; - } - txs_list[i] = block->transactions()[indexes[i]]; - } - - block_transactions response(message->block_hash(),txs_list); - SEND2(response, handle_send, _1, block_transactions::command); - } - }); - - return true; -} - - -// Receive get_blocks sequence. -//----------------------------------------------------------------------------- - -bool protocol_block_out::handle_receive_get_blocks(code const& ec, get_blocks_const_ptr message) { - if (stopped(ec)) { - return false; - } - - auto const size = message->start_hashes().size(); - - if (size > max_locator) { - spdlog::warn("[node] Excessive get_blocks locator size ({}) from [{}]", size, authority()); - stop(error::channel_stopped); - return false; - } - - if (size > locator_limit()) { - spdlog::debug("[node] Disallowed get_blocks locator size ({}) from [{}]", size, authority()); - return true; - } - - // Allow a peer to sync despite our being stale. - ////if (chain_.is_stale()) - //// return true; - - auto const threshold = last_locator_top_.load(); - - chain_.fetch_locator_block_hashes(message, threshold, max_get_blocks, BIND2(handle_fetch_locator_hashes, _1, _2)); - return true; -} - -void protocol_block_out::handle_fetch_locator_hashes(code const& ec, inventory_ptr message) { - if (stopped(ec)) { - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating locator block hashes for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - if (message->inventories().empty()) { - return; - } - - // Allow a peer to sync despite our being stale. - ////if (chain_.is_stale()) - //// return; - - // Respond to get_blocks with inventory. - SEND2(*message, handle_send, _1, message->command); - - // Save the locator top to limit an overlapping future request. - last_locator_top_.store(message->inventories().front().hash()); -} - -// Receive get_data sequence. -//----------------------------------------------------------------------------- - -// TODO: move compact_block to derived class protocol_block_out_70014. -// TODO: move filtered_block to derived class protocol_block_out_70001. -bool protocol_block_out::handle_receive_get_data(code const& ec, get_data_const_ptr message) { - if (stopped(ec)) { - return false; - } - - // TODO: consider rejecting the message for duplicated entries. - if (message->inventories().size() > max_get_data) { - spdlog::warn("[node] Invalid get_data size ({}) from [{}]", message->inventories().size(), authority()); - stop(error::channel_stopped); - return false; - } - - // Allow a peer to sync despite our being stale. - ////if (chain_.is_stale()) - //// return true; - - // Create a copy because message is const because it is shared. - auto const response = std::make_shared(); - - // TODO: convert all compact_block elements to block unless block is, - // "recently announced and ... close to the tip of the best chain". - // Close to the tip could be the tip itself with recent based on timestamp. - // Peer may request compact only after receipt of a send_compact message. - - // Reverse copy the block elements of the const inventory. - for (auto const inventory: reverse(message->inventories())) { - if (inventory.is_block_type()) { - response->inventories().push_back(inventory); - } - } - - send_next_data(response); - return true; -} - -void protocol_block_out::send_next_data(inventory_ptr inventory) { - if (inventory->inventories().empty()) { - return; - } - - // The order is reversed so that we can pop from the back. - auto const& entry = inventory->inventories().back(); - - switch (entry.type()) { - case inventory::type_id::block: { - chain_.fetch_block(entry.hash(), BIND4(send_block, _1, _2, _3, inventory)); - break; - } case inventory::type_id::filtered_block: { - chain_.fetch_merkle_block(entry.hash(), BIND4(send_merkle_block, _1, _2, _3, inventory)); - break; - } case inventory::type_id::compact_block: { - chain_.fetch_compact_block(entry.hash(), BIND4(send_compact_block, _1, _2, _3, inventory)); - break; - } default: { - KTH_ASSERT_MSG(false, "improperly-filtered inventory"); - } - } -} - -void protocol_block_out::send_block(code const& ec, block_const_ptr message, size_t, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - if (ec == error::not_found) { - spdlog::debug("[node] Block requested by [{}] not found.", authority()); - - // TODO: move not_found to derived class protocol_block_out_70001. - KTH_ASSERT( ! inventory->inventories().empty()); - not_found const reply{ inventory->inventories().back() }; - SEND2(reply, handle_send, _1, reply.command); - handle_send_next(error::success, inventory); - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating block requested by [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - SEND2(*message, handle_send_next, _1, inventory); -} - -// TODO: move merkle_block to derived class protocol_block_out_70001. -void protocol_block_out::send_merkle_block(code const& ec, merkle_block_const_ptr message, size_t, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - if (ec == error::not_found) { - spdlog::debug("[node] Merkle block requested by [{}] not found.", authority()); - - // TODO: move not_found to derived class protocol_block_out_70001. - KTH_ASSERT( ! inventory->inventories().empty()); - not_found const reply{ inventory->inventories().back() }; - SEND2(reply, handle_send, _1, reply.command); - handle_send_next(error::success, inventory); - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating merkle block requested by [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - SEND2(*message, handle_send_next, _1, inventory); -} - -// TODO: move compact_block to derived class protocol_block_out_70014. -void protocol_block_out::send_compact_block(code const& ec, compact_block_const_ptr message, size_t, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - if (ec == error::not_found) { - spdlog::debug("[node] Compact block requested by [{}] not found.", authority()); - - // TODO: move not_found to derived class protocol_block_out_70001. - KTH_ASSERT( ! inventory->inventories().empty()); - not_found const reply{ inventory->inventories().back() }; - SEND2(reply, handle_send, _1, reply.command); - handle_send_next(error::success, inventory); - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating compact block requested by [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - SEND2(*message, handle_send_next, _1, inventory); -} - -void protocol_block_out::handle_send_next(code const& ec, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - KTH_ASSERT( ! inventory->inventories().empty()); - inventory->inventories().pop_back(); - - // Break off recursion. - DISPATCH_CONCURRENT1(send_next_data, inventory); -} - -// Subscription. -//----------------------------------------------------------------------------- - -// TODO: add consideration for catch-up, where we may not want to announce. -// We never announce or inventory an orphan, only indexed blocks. -bool protocol_block_out::handle_reorganized(code ec, size_t fork_height, block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr) { - if (stopped(ec)) { - return false; - } - - if (ec) { - spdlog::error("[node] Failure handling reorganization: {}", ec.message()); - stop(ec); - return false; - } - - // Nothing to do, a channel is stopping but it's not this one. - if ( ! incoming || incoming->empty()) { - return true; - } - - // Do not announce blocks to peer if too far behind. - if (chain_.is_stale()) { - return true; - } - - // TODO: consider always sending the last block as compact if enabled. - if (compact_to_peer_ && compact_high_bandwidth_ && incoming->size() == 1) { - // TODO: move compact_block to a derived class protocol_block_in_70014. - auto const block = incoming->front(); - - if (block->validation.originator != nonce()) { - compact_block announce = compact_block::factory_from_block(*block); - SEND2(announce, handle_send, _1, announce.command); - } - - return true; - } else if (headers_to_peer_) { - // TODO: move headers to a derived class protocol_block_in_70012. - headers announce; - - for (auto const block: *incoming) { - if (block->validation.originator != nonce()) { - announce.elements().push_back(block->header()); - } - } - - if ( ! announce.elements().empty()) { - SEND2(announce, handle_send, _1, announce.command); - ////auto const hash = announce.elements().front().hash(); - ////spdlog::debug("[node] - ////] Announced block header [{}] to [{}].", encode_hash(hash) - ////, authority()); - } - - return true; - } else { - inventory announce; - - for (auto const block: *incoming) { - if (block->validation.originator != nonce()) { - announce.inventories().push_back({ inventory::type_id::block, block->header().hash() }); - } - } - - if ( ! announce.inventories().empty()) { - SEND2(announce, handle_send, _1, announce.command); - ////auto const hash = announce.inventories().front().hash(); - ////spdlog::debug("[node] - ////] Announced block inventory [{}] to [{}].", encode_hash(hash) - ////, authority()); - } - - return true; - } -} - -void protocol_block_out::handle_stop(code const&) { - chain_.unsubscribe(); - spdlog::debug("[network] Stopped block_out protocol for [{}].", authority()); -} - -// Utility. -//----------------------------------------------------------------------------- - -// The locator cannot be longer than allowed by our chain length. -// This is DoS protection, otherwise a peer could tie up our database. -// If we are not synced to near the height of peers then this effectively -// prevents peers from syncing from us. Ideally we should use initial block -// download to get close before enabling the block out protocol in any case. -// Note that always populating a locator from the main chain results in an -// effective limit on reorganization depth. The outer limit is 500 or 2000 -// depending on the protocol in use. However the peers starts from the first -// point of agreement, meaning that after the first 10 locator hashes this is -// reduced by the size of the gap. The largest cumulative gap is the sum of -// 2^n for n where n > 1 where the sum is < 500 - 10. So Bitcoin reorganization -// is protocol-limited to depth 256 + 10 = 266, unless nodes grow forks by -// generating fork-relative locators. -size_t protocol_block_out::locator_limit() { - auto const height = node_.top_block().height(); - return *safe_add(domain::chain::block::locator_size(height), size_t(1)); -} - -// Threshold: -// The peer threshold prevents a peer from creating an unnecessary backlog -// for itself in the case where it is requesting without having processed -// all of its existing backlog. This also reduces its load on us. -// This could cause a problem during a reorg, where the peer regresses -// and one of its other peers populates the chain back to this level. In -// that case we would not respond but our peer's other peer should. -// Other than a reorg there is no reason for the peer to regress, as -// locators are only useful in walking up the chain. - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_block_sync.cpp b/src/node/src/protocols/protocol_block_sync.cpp deleted file mode 100644 index 2ae214f9..00000000 --- a/src/node/src/protocols/protocol_block_sync.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include - -namespace kth::node { - -#define NAME "block_sync" -#define CLASS protocol_block_sync - -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -// The interval in which block download rate is tested. -static const asio::seconds expiry_interval(5); - -// Depends on protocol_header_sync, which requires protocol version 31800. -protocol_block_sync::protocol_block_sync(full_node& network, channel::ptr channel, reservation::ptr row) - : protocol_timer(network, channel, true, NAME) - , reservation_(row) - , CONSTRUCT_TRACK(protocol_block_sync) -{} - -// Start sequence. -// ---------------------------------------------------------------------------- - -void protocol_block_sync::start(event_handler handler) { - auto const complete = synchronize(BIND2(blocks_complete, _1, handler), 1, NAME); - - protocol_timer::start(expiry_interval, BIND2(handle_event, _1, complete)); - - SUBSCRIBE3(block, handle_receive_block, _1, _2, complete); - - // This is the end of the start sequence. - send_get_blocks(complete, true); -} - -// Peer sync sequence. -// ---------------------------------------------------------------------------- - -void protocol_block_sync::send_get_blocks(event_handler complete, bool reset) { - if (stopped()) { - return; - } - - if (reservation_->stopped()) { - spdlog::debug("[node] Stopping complete slot ({}).", reservation_->slot()); - complete(error::success); - return; - } - - // We may be a new channel (reset) or may have a new packet. - auto const request = reservation_->request(reset); - - // Or we may be the same channel and with hashes already requested. - if (request.inventories().empty()) { - return; - } - - spdlog::debug("[node] Sending request of {} hashes for slot ({}).", request.inventories().size(), reservation_->slot()); - - SEND2(request, handle_send, _1, request.command); -} - -// The message subscriber implements an optimization to bypass queueing of -// block messages. This requires that this handler never call back into the -// subscriber. Otherwise a deadlock will result. This in turn requires that -// the 'complete' parameter handler never call into the message subscriber. -bool protocol_block_sync::handle_receive_block(code const& ec, block_const_ptr message, event_handler complete) { - if (stopped(ec)) { - return false; - } - - spdlog::info("[node] protocol_block_sync::handle_receive_block ***********************************************************"); - -#if ! defined(KTH_DB_READONLY) - // Add the block to the blockchain store. - reservation_->import(message); -#endif - - if (reservation_->toggle_partitioned()) { - spdlog::debug("[node] Restarting partitioned slot ({}).", reservation_->slot()); - complete(error::channel_stopped); - return false; - } - - // Request more blocks if our reservation has been expanded. - send_get_blocks(complete, false); - return true; -} - -// This is fired by the base timer and stop handler. -void protocol_block_sync::handle_event(code const& ec, event_handler complete) { - if (stopped(ec)) { - return; - } - - if (ec && ec != error::channel_timeout) { - spdlog::debug("[node] Failure in block sync timer for slot ({}) {}", reservation_->slot(), ec.message()); - complete(ec); - return; - } - - // This results from other channels taking this channel's hashes in - // combination with this channel's peer not responding to the last request. - // Causing a successful stop here prevents channel startup just to stop. - if (reservation_->stopped()) { - spdlog::debug("[node] Stopping complete slot ({}).", reservation_->slot()); - complete(error::success); - return; - } - - if (reservation_->expired()) { - spdlog::debug("[node] Restarting slow slot ({})", reservation_->slot()); - complete(error::channel_timeout); - return; - } -} - -void protocol_block_sync::blocks_complete(code const& ec, event_handler handler) { - // We are no longer receiving blocks, so exclude from average. - reservation_->reset(); - - // This is the end of the peer sync sequence. - // If there is no error the hash list must be empty and remain so. - handler(ec); - - // The session does not need to handle the stop. - stop(error::channel_stopped); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_double_spend_proof_in.cpp b/src/node/src/protocols/protocol_double_spend_proof_in.cpp deleted file mode 100644 index e98bbba1..00000000 --- a/src/node/src/protocols/protocol_double_spend_proof_in.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include -#include -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -#define NAME "double_spend_proof_in" -#define CLASS protocol_double_spend_proof_in - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -protocol_double_spend_proof_in::protocol_double_spend_proof_in(full_node& node, channel::ptr channel, safe_chain& chain) - : protocol_events(node, channel, NAME) - , chain_(chain) - , ds_proofs_enabled_(node.node_settings().ds_proofs_enabled) - , CONSTRUCT_TRACK(protocol_double_spend_proof_in) -{} - -// Start. -//----------------------------------------------------------------------------- - -void protocol_double_spend_proof_in::start() { - protocol_events::start(BIND1(handle_stop, _1)); - - SUBSCRIBE2(inventory, handle_receive_inventory, _1, _2); - SUBSCRIBE2(double_spend_proof, handle_receive_ds_proof_data, _1, _2); -} - -// Receive inventory sequence. -//----------------------------------------------------------------------------- - -bool protocol_double_spend_proof_in::handle_receive_inventory(code const& ec, inventory_const_ptr message) { - if (stopped(ec)) { - return false; - } - - // Do not process DSProof inventory while chain is stale. - if (chain_.is_stale()) { - return true; - } - - auto const response = std::make_shared(); - - // Copy the DSProof inventories into a get_data instance. - message->reduce(response->inventories(), inventory::type_id::double_spend_proof); - - if (message->inventories().empty()) { - return true; - } - - if ( ! ds_proofs_enabled_) { - spdlog::debug("[node] Got DSProof INV but node.ds_proofs is disabled (settings) from [{}]", authority()); - return true; - } - // BCHN: inv.hash.ToString() - - spdlog::debug("[node] Got DSProof INV from [{}]", authority()); - - // if (DoubleSpendProof::IsEnabled()) { - // // dsproof subsystem enabled, ask peer for the proof - // LogPrint(BCLog::DSPROOF, "Got DSProof INV %s\n", inv.hash.ToString()); - // connman->PushMessage(pfrom, - // msgMaker.Make(NetMsgType::GETDATA, std::vector{inv})); - // } else { - // // dsproof subsystem disabled, ignore this inv - // LogPrint(BCLog::DSPROOF, "Got DSProof INV %s (ignored, -doublespendproof=0)\n", - // inv.hash.ToString()); - // } - - send_get_data(ec, response); - return true; -} - -void protocol_double_spend_proof_in::send_get_data(code const& ec, get_data_ptr message) { - if (stopped(ec) || message->inventories().empty()) { - return; - } - - SEND2(*message, handle_send, _1, message->command); -} - -// Receive DSProof data. -//----------------------------------------------------------------------------- - -// A DSProof msg is acceptable whether solicited or broadcast. -bool protocol_double_spend_proof_in::handle_receive_ds_proof_data(code const& ec, double_spend_proof_const_ptr message) { - - if (stopped(ec)) { - return false; - } - - // TODO: manage channel relay at the service layer. - // Do not process DSProofs while chain is stale. - if (chain_.is_stale()) { - return true; - } - - chain_.organize(message, BIND2(handle_store_ds_proof_data, _1, message)); - return true; -} - -// The DSProof has been saved into the storage. -// This will be picked up by subscription in double_spend_proof_out and will cause -// the DSProof to be announced to non-originating relay-accepting peers. -void protocol_double_spend_proof_in::handle_store_ds_proof_data(code const& ec, double_spend_proof_const_ptr message) { - if (stopped(ec)) { - return; - } - - auto const encoded = encode_hash(message->hash()); - - if (ec) { - // This should not happen with a single peer since we filter inventory. - // However it will happen when a block or another peer's tx intervenes. - spdlog::debug("[node] Dropped DSProof [{}] from [{}] {}", encoded, authority(), ec.message()); - return; - } - - spdlog::debug("[node] Stored DSProof [{}] from [{}].", encoded, authority()); -} - -// Stop. -//----------------------------------------------------------------------------- - -void protocol_double_spend_proof_in::handle_stop(code const&) { - spdlog::debug("[network] Stopped double_spend_proof_in protocol for [{}].", authority()); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_double_spend_proof_out.cpp b/src/node/src/protocols/protocol_double_spend_proof_out.cpp deleted file mode 100644 index 7b4ed374..00000000 --- a/src/node/src/protocols/protocol_double_spend_proof_out.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include - -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -#define NAME "double_spend_proof_out" -#define CLASS protocol_double_spend_proof_out - -using namespace kth::blockchain; -using namespace kth::domain::chain; -using namespace kth::database; -using namespace kth::domain::message; -using namespace kth::network; -using namespace boost::adaptors; -using namespace std::placeholders; - -protocol_double_spend_proof_out::protocol_double_spend_proof_out(full_node& node, channel::ptr channel, safe_chain& chain) - : protocol_events(node, channel, NAME) - , chain_(chain) - , ds_proofs_enabled_(node.node_settings().ds_proofs_enabled) - , CONSTRUCT_TRACK(protocol_double_spend_proof_out) -{} - -// Start. -//----------------------------------------------------------------------------- - -void protocol_double_spend_proof_out::start() { - protocol_events::start(BIND1(handle_stop, _1)); - - // Prior to this level DSProof relay is not configurable. - if (ds_proofs_enabled_) { - // Subscribe to DSProof pool notifications and relay txs. - chain_.subscribe_ds_proof(BIND2(handle_ds_proof_pool, _1, _2)); - } - - SUBSCRIBE2(get_data, handle_receive_get_data, _1, _2); -} - -// Receive get_data sequence. -//----------------------------------------------------------------------------- - -bool protocol_double_spend_proof_out::handle_receive_get_data(code const& ec, get_data_const_ptr message) { - if (stopped(ec)) { - return false; - } - - if ( ! ds_proofs_enabled_) { - spdlog::debug("[node] Got DSProof GetData but node.ds_proofs is disabled (settings) from [{}]", authority()); - return false; - } - - if (message->inventories().size() > max_get_data) { - spdlog::warn("[node] Invalid get_data size ({}) from [{}]", message->inventories().size(), authority()); - stop(error::channel_stopped); - return false; - } - - // Create a copy because message is const because it is shared. - auto const response = std::make_shared(); - - // Reverse copy the DSProof elements of the const inventory. - for (auto const inventory: reverse(message->inventories())) { - if (inventory.is_double_spend_proof_type()) { - response->inventories().push_back(inventory); - } - } - - send_next_data(response); - return true; -} - -void protocol_double_spend_proof_out::send_next_data(inventory_ptr inventory) { - if (inventory->inventories().empty()) { - return; - } - - // The order is reversed so that we can pop from the back. - auto const& entry = inventory->inventories().back(); - - switch (entry.type()) { - case inventory::type_id::double_spend_proof: { - chain_.fetch_ds_proof(entry.hash(), BIND3(send_ds_proof, _1, _2, inventory)); - break; - } default: { - KTH_ASSERT_MSG(false, "improperly-filtered inventory"); - } - } -} - -void protocol_double_spend_proof_out::send_ds_proof(code const& ec, double_spend_proof_const_ptr message, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - if (ec == error::not_found) { - spdlog::debug("[node] DSProof requested by [{}] not found.", authority()); - - KTH_ASSERT( ! inventory->inventories().empty()); - not_found const reply{ inventory->inventories().back() }; - SEND2(reply, handle_send, _1, reply.command); - handle_send_next(error::success, inventory); - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating DSProof requested by [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - SEND2(*message, handle_send_next, _1, inventory); -} - -void protocol_double_spend_proof_out::handle_send_next(code const& ec, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - KTH_ASSERT( ! inventory->inventories().empty()); - inventory->inventories().pop_back(); - - // Break off recursion. - DISPATCH_CONCURRENT1(send_next_data, inventory); -} - -// Subscription. -//----------------------------------------------------------------------------- - -bool protocol_double_spend_proof_out::handle_ds_proof_pool(code const& ec, double_spend_proof_const_ptr message) { - if (stopped(ec)) { - return false; - } - - if (ec) { - spdlog::error("[node] Failure handling DSProof notification: {}", ec.message()); - stop(ec); - return false; - } - - // TODO: make this a collection and send empty in this case. - // Nothing to do, a channel is stopping but it's not this one. - if ( ! message) { - return true; - } - - // Do not announce DSProofs to peer if too far behind. - // Typically the tx would not validate anyway, but this is more consistent. - if (chain_.is_stale()) { - return true; - } - - inventory::type_id id = inventory::type_id::double_spend_proof; - inventory const announce {{id, message->hash()}}; - SEND2(announce, handle_send, _1, announce.command); - - ////spdlog::debug("[node] - ////] Announced tx [{}{}{}].", encode_hash(message->hash()), "] to [" - ////, authority()); - return true; -} - -void protocol_double_spend_proof_out::handle_stop(code const&) { - chain_.unsubscribe(); - - spdlog::debug("[network] Stopped double_spend_proof_out protocol for [{}].", authority()); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_header_sync.cpp b/src/node/src/protocols/protocol_header_sync.cpp deleted file mode 100644 index 33b3934c..00000000 --- a/src/node/src/protocols/protocol_header_sync.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include - -namespace kth::node { - -#define NAME "header_sync" -#define CLASS protocol_header_sync - -using namespace kth::domain::config; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -// The interval in which header download rate is measured and tested. -static const asio::seconds expiry_interval(5); - -// This class requires protocol version 31800. -protocol_header_sync::protocol_header_sync(full_node& network, channel::ptr channel, header_list::ptr headers, uint32_t minimum_rate) - : protocol_timer(network, channel, true, NAME) - , headers_(headers) - - // TODO: replace rate backoff with peer competition. - //========================================================================= - , current_second_(0) - , minimum_rate_(minimum_rate) - , start_size_(headers->previous_height() - headers->first_height()) - //========================================================================= - , CONSTRUCT_TRACK(protocol_header_sync) -{} - -// Start sequence. -// ---------------------------------------------------------------------------- - -void protocol_header_sync::start(event_handler handler) { - auto const complete = synchronize(BIND2(headers_complete, _1, handler), 1, NAME); - - protocol_timer::start(expiry_interval, BIND2(handle_event, _1, complete)); - - SUBSCRIBE3(headers, handle_receive_headers, _1, _2, complete); - - // This is the end of the start sequence. - send_get_headers(complete); -} - -// Header sync sequence. -// ---------------------------------------------------------------------------- - -void protocol_header_sync::send_get_headers(event_handler complete) { - if (stopped()) { - return; - } - - get_headers const request { - {headers_->previous_hash()}, - headers_->stop_hash() - }; - - spdlog::info("[node] protocol_header_sync::send_get_headers [{}]", authority()); - SEND2(request, handle_send, _1, request.command); -} - -bool protocol_header_sync::handle_receive_headers(code const& ec, headers_const_ptr message, event_handler complete) { - if (stopped(ec)) { - return false; - } - - auto const start = headers_->previous_height() + 1; - - // A merge failure resets the headers list. - if ( ! headers_->merge(message)) { - spdlog::warn("[node] Failure merging headers from [{}]", authority()); - complete(error::invalid_previous_block); - return false; - } - - auto const end = headers_->previous_height(); - - spdlog::info("[node] Synced headers {}-{} from [{}]", start, end, authority()); - - if (headers_->complete()) { - complete(error::success); - return false; - } - - // If we received fewer than 2000 the peer is exhausted, try another. - if (message->elements().size() < max_get_headers) { - complete(error::operation_failed); - return false; - } - - // This peer has more headers. - send_get_headers(complete); - return true; -} - -// This is fired by the base timer and stop handler. -void protocol_header_sync::handle_event(code const& ec, event_handler complete) { - if (stopped(ec)) { - return; - } - - if (ec && ec != error::channel_timeout) { - spdlog::warn("[node] Failure in header sync timer for [{}] {}", authority(), ec.message()); - complete(ec); - return; - } - - // TODO: replace rate backoff with peer competition. - //========================================================================= - // It was a timeout so another expiry period has passed (overflow ok here). - current_second_ += size_t(expiry_interval.count()); - auto rate = (headers_->previous_height() - start_size_) / current_second_; - //========================================================================= - - // Drop the channel if it falls below the min sync rate averaged over all. - if (rate < minimum_rate_) { - spdlog::debug("[node] Header sync rate ({}/sec) from [{}]", rate, authority()); - complete(error::channel_timeout); - return; - } -} - -void protocol_header_sync::headers_complete(code const& ec, event_handler handler) { - // This is end of the header sync sequence. - handler(ec); - - // The session does not need to handle the stop. - stop(error::channel_stopped); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_transaction_in.cpp b/src/node/src/protocols/protocol_transaction_in.cpp deleted file mode 100644 index c6fa239c..00000000 --- a/src/node/src/protocols/protocol_transaction_in.cpp +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include -#include -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -#define NAME "transaction_in" -#define CLASS protocol_transaction_in - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -inline -uint64_t to_relay_fee(float minimum_byte_fee) { - // Spending one standard prevout with one output is nominally 189 bytes. - static size_t const small_transaction_size = 189; - return uint64_t(minimum_byte_fee * small_transaction_size); -} - -protocol_transaction_in::protocol_transaction_in(full_node& node, channel::ptr channel, safe_chain& chain) - : protocol_events(node, channel, NAME) - , chain_(chain) - - // TODO: move fee_filter to a derived class protocol_transaction_in_70013. - , minimum_relay_fee_(negotiated_version() >= version::level::bip133 ? - to_relay_fee(node.chain_settings().byte_fee_satoshis) : 0) - - // TODO: move relay to a derived class protocol_transaction_in_70001. - // In the mean time, restrict by negotiated protocol level. - // Because of inconsistent implementation by version we must allow relay - // at bip37 version or below. Enforcement starts above bip37 version. - , relay_from_peer_(negotiated_version() <= version::level::bip37 || - node.network_settings().relay_transactions) - - // TODO: move memory_pool to a derived class protocol_transaction_in_60002. - , refresh_pool_(negotiated_version() >= version::level::bip35 && - node.node_settings().refresh_transactions) - - , CONSTRUCT_TRACK(protocol_transaction_in) -{} - -// Start. -//----------------------------------------------------------------------------- - -void protocol_transaction_in::start() { - - protocol_events::start(BIND1(handle_stop, _1)); - - SUBSCRIBE2(inventory, handle_receive_inventory, _1, _2); - SUBSCRIBE2(transaction, handle_receive_transaction, _1, _2); - - // TODO: move fee_filter to a derived class protocol_transaction_in_70013. - if (minimum_relay_fee_ != 0) { - // Have the peer filter the transactions it announces to us. - SEND2(fee_filter{minimum_relay_fee_}, handle_send, _1, fee_filter::command); - } - - // TODO: move memory_pool to a derived class protocol_transaction_in_60002. - if (refresh_pool_ && relay_from_peer_ && !chain_.is_stale()) { - // Refresh transaction pool on connect. - SEND2(memory_pool{}, handle_send, _1, memory_pool::command); - } -} - -// Receive inventory sequence. -//----------------------------------------------------------------------------- - -bool protocol_transaction_in::handle_receive_inventory(code const& ec, inventory_const_ptr message) { - if (stopped(ec)) { - return false; - } - - auto const response = std::make_shared(); - - // Copy the transaction inventories into a get_data instance. - message->reduce(response->inventories(), inventory::type_id::transaction); - - // TODO: move relay to a derived class protocol_transaction_in_70001. - // Prior to this level transaction relay is not configurable. - if ( ! relay_from_peer_ && ! response->inventories().empty()) { - spdlog::warn("[node] Unexpected transaction inventory from [{}]", authority()); - stop(error::channel_stopped); - return false; - } - - // TODO: manage channel relay at the service layer. - // Do not process tx inventory while chain is stale. - if (chain_.is_stale()) { - return true; - } - - // Remove hashes of (unspent) transactions that we already have. - // BUGBUG: this removes spent transactions which it should not (see BIP30). - - // spdlog::info("[node] send_get_transactions() - before filter_transactions - 1"); - chain_.filter_transactions(response, BIND2(send_get_data, _1, response)); - return true; -} - -void protocol_transaction_in::send_get_data(code const& ec, get_data_ptr message) { - if (stopped(ec) || message->inventories().empty()) { - return; - } - - if (ec) { - spdlog::error("[node] Internal failure filtering transaction hashes for [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - // inventory->get_data[transaction] - SEND2(*message, handle_send, _1, message->command); -} - -// Receive transaction sequence. -//----------------------------------------------------------------------------- - -// A transaction is acceptable whether solicited or broadcast. -bool protocol_transaction_in::handle_receive_transaction(code const& ec, transaction_const_ptr message) { - - if (stopped(ec)) { - return false; - } - - // TODO: move relay to a derived class protocol_transaction_in_70001. - // Prior to this level transaction relay is not configurable. - if ( ! relay_from_peer_) { - spdlog::debug("[node] Unexpected transaction relay from [{}]", authority()); - stop(error::channel_stopped); - return false; - } - - // TODO: manage channel relay at the service layer. - // Do not process transactions while chain is stale. - if (chain_.is_stale()) { - return true; - } - - message->validation.originator = nonce(); - chain_.organize(message, BIND2(handle_store_transaction, _1, message)); - return true; -} - -// The transaction has been saved to the memory pool (or not). -// This will be picked up by subscription in transaction_out and will cause -// the transaction to be announced to non-originating relay-accepting peers. -void protocol_transaction_in::handle_store_transaction(code const& ec, transaction_const_ptr message) { - if (stopped(ec)) { - return; - } - - // Ask the peer for ancestor txs if this one is an orphan. - // We may not get this transaction back, but that is a fair tradeoff for - // not having to store potentially invalid transactions. - if (ec == error::orphan_transaction) { - send_get_transactions(message); - } - - auto const encoded = encode_hash(message->hash()); - - // It is okay for us to receive a duplicate or a missing outputs tx but it - // is not generally okay to receive an otherwise invalid transaction. - // Below-fee transactions can be sent prior to fee_filter receipt or due to - // a negotiated version below BIP133 (7013). - - // TODO: differentiate failure conditions and send reject as applicable. - - if (ec) { - // This should not happen with a single peer since we filter inventory. - // However it will happen when a block or another peer's tx intervenes. - spdlog::debug("[node] Dropped transaction [{}] from [{}] {}", encoded, authority(), ec.message()); - return; - } - - spdlog::debug("[node] Stored transaction [{}] from [{}].", encoded, authority()); -} - -// This will get chatty if the peer sends mempool response out of order. -// This requests the next level of missing tx, but those may be orphans as -// well. Those would also be discarded, until arriving at connectable txs. -// There is no facility to re-obtain the dropped transactions. They must be -// obtained coincidentally by peers, by a mempool message (new channel) or as a -// result of transaction resends. -void protocol_transaction_in::send_get_transactions(transaction_const_ptr message) { - inventory::type_id type = inventory::type_id::transaction; - - auto missing = message->missing_previous_transactions(); - - if (missing.empty()) { - return; - } - - auto const request = std::make_shared(std::move(missing), type); - - // Remove hashes of (unspent) transactions that we already have. - // This removes spent transactions which is not correnct, however given the - // treatment of duplicate hashes by other nodes and the fact that this is - // a set of pool transactions only, this is okay. - - // spdlog::info("[node] send_get_transactions() - before filter_transactions - 2"); - chain_.filter_transactions(request, BIND2(send_get_data, _1, request)); -} - -// Stop. -//----------------------------------------------------------------------------- - -void protocol_transaction_in::handle_stop(code const&) { - spdlog::debug("[network] Stopped transaction_in protocol for [{}].", authority()); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/protocols/protocol_transaction_out.cpp b/src/node/src/protocols/protocol_transaction_out.cpp deleted file mode 100644 index f1d0ffe2..00000000 --- a/src/node/src/protocols/protocol_transaction_out.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include - -#include - -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include - -namespace kth::node { - -#define NAME "transaction_out" -#define CLASS protocol_transaction_out - -using namespace kth::blockchain; -using namespace kth::domain::chain; -using namespace kth::database; -using namespace kth::domain::message; -using namespace kth::network; -using namespace boost::adaptors; -using namespace std::placeholders; - -protocol_transaction_out::protocol_transaction_out(full_node& network, channel::ptr channel, safe_chain& chain) - : protocol_events(network, channel, NAME) - , chain_(chain) - - // TODO: move fee filter to a derived class protocol_transaction_out_70013. - , minimum_peer_fee_(0) - - // TODO: move relay to a derived class protocol_transaction_out_70001. - , relay_to_peer_(peer_version()->relay()) - - , CONSTRUCT_TRACK(protocol_transaction_out) -{} - -// TODO: move not_found to derived class protocol_transaction_out_70001. - -// Start. -//----------------------------------------------------------------------------- - -void protocol_transaction_out::start() { - protocol_events::start(BIND1(handle_stop, _1)); - - // TODO: move relay to a derived class protocol_transaction_out_70001. - // Prior to this level transaction relay is not configurable. - if (relay_to_peer_) { - // Subscribe to transaction pool notifications and relay txs. - chain_.subscribe_transaction(BIND2(handle_transaction_pool, _1, _2)); - } - - // TODO: move fee filter to a derived class protocol_transaction_out_70013. - SUBSCRIBE2(fee_filter, handle_receive_fee_filter, _1, _2); - - // TODO: move memory pool to a derived class protocol_transaction_out_60002. - SUBSCRIBE2(memory_pool, handle_receive_memory_pool, _1, _2); - SUBSCRIBE2(get_data, handle_receive_get_data, _1, _2); -} - -// Receive send_headers. -//----------------------------------------------------------------------------- - -// TODO: move fee_filters to a derived class protocol_transaction_out_70013. -bool protocol_transaction_out::handle_receive_fee_filter(code const& ec, fee_filter_const_ptr message) { - if (stopped(ec)) { - return false; - } - - // TODO: move fee filter to a derived class protocol_transaction_out_70013. - // Transaction annoucements will be filtered by fee amount. - minimum_peer_fee_ = message->minimum_fee(); - - // The fee filter may be adjusted. - return true; -} - -// Receive mempool sequence. -//----------------------------------------------------------------------------- - -// TODO: move memory_pool to a derived class protocol_transaction_out_60002. -bool protocol_transaction_out::handle_receive_memory_pool(code const& ec, memory_pool_const_ptr) { - if (stopped(ec)) { - return false; - } - - // The handler may be invoked *multiple times* by one blockchain call. - // TODO: move multiple mempool inv to protocol_transaction_out_70002. - // TODO: move fee filter to a derived class protocol_transaction_out_70013. - chain_.fetch_mempool(max_inventory, minimum_peer_fee_, BIND2(handle_fetch_mempool, _1, _2)); - - // Drop this subscription after the first request. - return false; -} - -// Each invocation is limited to 50000 vectors and invoked from common thread. -void protocol_transaction_out::handle_fetch_mempool(code const& ec, inventory_ptr message) { - if (stopped(ec) || message->inventories().empty()) { - return; - } - - SEND2(*message, handle_send, _1, message->command); -} - -// Receive get_data sequence. -//----------------------------------------------------------------------------- - -// THIS SUPPORTS REQUEST OF CONFIRMED TRANSACTIONS. -// TODO: subscribe to and handle get_block_transactions message. -// TODO: expose a new service bit that indicates complete current tx history. -// This would exclude transctions replaced by duplication as per BIP30. -bool protocol_transaction_out::handle_receive_get_data(code const& ec, get_data_const_ptr message) { - if (stopped(ec)) { - return false; - } - - if (message->inventories().size() > max_get_data) { - spdlog::warn("[node] Invalid get_data size ({}) from [{}]", message->inventories().size(), authority()); - stop(error::channel_stopped); - return false; - } - - // Create a copy because message is const because it is shared. - auto const response = std::make_shared(); - - // Reverse copy the transaction elements of the const inventory. - for (auto const inventory: reverse(message->inventories())) { - if (inventory.is_transaction_type()) { - response->inventories().push_back(inventory); - } - } - - send_next_data(response); - return true; -} - -void protocol_transaction_out::send_next_data(inventory_ptr inventory) { - if (inventory->inventories().empty()) { - return; - } - - // The order is reversed so that we can pop from the back. - auto const& entry = inventory->inventories().back(); - - switch (entry.type()) { - case inventory::type_id::transaction: { - chain_.fetch_transaction(entry.hash(), false, BIND5(send_transaction, _1, _2, _3, _4, inventory)); - break; - } default: { - KTH_ASSERT_MSG(false, "improperly-filtered inventory"); - } - } -} - -// TODO: send block_transaction message as applicable. -void protocol_transaction_out::send_transaction(code const& ec, transaction_const_ptr message, size_t position, size_t /*height*/, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - // Treat already confirmed transactions as not found. - auto confirmed = ! ec - && position != position_max - ; - - if (ec == error::not_found || confirmed) { - spdlog::debug("[node] Transaction requested by [{}] not found.", authority()); - - // TODO: move not_found to derived class protocol_block_out_70001. - KTH_ASSERT( ! inventory->inventories().empty()); - not_found const reply{ inventory->inventories().back() }; - SEND2(reply, handle_send, _1, reply.command); - handle_send_next(error::success, inventory); - return; - } - - if (ec) { - spdlog::error("[node] Internal failure locating transaction requested by [{}] {}", authority(), ec.message()); - stop(ec); - return; - } - - SEND2(*message, handle_send_next, _1, inventory); -} - -void protocol_transaction_out::handle_send_next(code const& ec, inventory_ptr inventory) { - if (stopped(ec)) { - return; - } - - KTH_ASSERT( ! inventory->inventories().empty()); - inventory->inventories().pop_back(); - - // Break off recursion. - DISPATCH_CONCURRENT1(send_next_data, inventory); -} - -// Subscription. -//----------------------------------------------------------------------------- - -bool protocol_transaction_out::handle_transaction_pool(code const& ec, transaction_const_ptr message) { - if (stopped(ec)) { - return false; - } - - if (ec) { - spdlog::error("[node] Failure handling transaction notification: {}", ec.message()); - stop(ec); - return false; - } - - // TODO: make this a collection and send empty in this case. - // Nothing to do, a channel is stopping but it's not this one. - if ( ! message) { - return true; - } - - // Do not announce transactions to peer if too far behind. - // Typically the tx would not validate anyway, but this is more consistent. - if (chain_.is_stale()) { - return true; - } - - if (message->validation.originator == nonce()) { - return true; - } - - // TODO: move fee_filter to a derived class protocol_transaction_out_70013. - if (message->fees() < minimum_peer_fee_) { - return true; - } - - inventory::type_id id; - id = inventory::type_id::transaction; - inventory const announce {{id, message->hash()}}; - SEND2(announce, handle_send, _1, announce.command); - - ////spdlog::debug("[node] - ////] Announced tx [{}{}{}].", encode_hash(message->hash()), "] to [" - ////, authority()); - return true; -} - -void protocol_transaction_out::handle_stop(code const&) { - chain_.unsubscribe(); - - spdlog::debug("[network] Stopped transaction_out protocol for [{}].", authority()); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/sessions/session_block_sync.cpp b/src/node/src/sessions/session_block_sync.cpp deleted file mode 100644 index f8325cc3..00000000 --- a/src/node/src/sessions/session_block_sync.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include -#include -#include -#include - -namespace kth::node { - -#define CLASS session_block_sync -#define NAME "session_block_sync" - -using namespace kth::blockchain; -using namespace kth::domain::config; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -// The interval in which all-channel block download performance is tested. -static const asio::seconds regulator_interval(5); - -session_block_sync::session_block_sync(full_node& network, check_list& hashes, fast_chain& chain, settings const& settings) - : session(network, false) - , chain_(chain) - , reservations_(hashes, chain, settings) - , CONSTRUCT_TRACK(session_block_sync) -{} - -// Start sequence. -// ---------------------------------------------------------------------------- - -void session_block_sync::start(result_handler handler) { - // TODO: create session_timer base class and pass interval via start. - timer_ = std::make_shared(pool_, regulator_interval); - session::start(CONCURRENT_DELEGATE2(handle_started, _1, handler)); -} - -void session_block_sync::handle_started(code const& ec, result_handler handler) { - if (ec) { - handler(ec); - return; - } - - // TODO: expose block count from reservations and emit here. - spdlog::info("[node] Getting blocks."); - - // Copy the reservations table. - auto const table = reservations_.table(); - - if (table.empty()) { - handler(error::success); - return; - } - - if ( ! reservations_.start()) { - spdlog::debug("[node] Failed to set write lock."); - handler(error::operation_failed); - return; - } - - auto const complete = synchronize(BIND2(handle_complete, _1, handler), table.size(), NAME); - - // This is the end of the start sequence. - for (auto const row : table) { - new_connection(row, complete); - } - - ////reset_timer(); -} - -// Block sync sequence. -// ---------------------------------------------------------------------------- - -void session_block_sync::new_connection(reservation::ptr row, result_handler handler) { - if (stopped()) { - spdlog::debug("[node] Suspending block slot ({}).", row ->slot()); - return; - } - - spdlog::debug("[node] Starting block slot ({}).", row->slot()); - - // BLOCK SYNC CONNECT - session_batch::connect(BIND4(handle_connect, _1, _2, row, handler)); -} - -void session_block_sync::handle_connect(code const& ec, channel::ptr channel, reservation::ptr row, result_handler handler) { - if (ec) { - spdlog::debug("[node] Failure connecting block slot ({}) {}", row->slot(), ec.message()); - new_connection(row, handler); - return; - } - - spdlog::debug("[node] Connected block slot ({}) [{}]", row->slot(), channel->authority()); - - register_channel(channel, - BIND4(handle_channel_start, _1, channel, row, handler), - BIND2(handle_channel_stop, _1, row)); -} - -void session_block_sync::attach_handshake_protocols(channel::ptr channel, result_handler handle_started) { - // Don't use configured services or relay for block sync. - auto const relay = false; - auto const own_version = settings_.protocol_maximum; - auto const own_services = version::service::none; - auto const invalid_services = settings_.invalid_services; - auto const minimum_version = settings_.protocol_minimum; - auto const minimum_services = version::service::node_network; - - // The negotiated_version is initialized to the configured maximum. - if (channel->negotiated_version() >= version::level::bip61) { - attach(channel, own_version, own_services, invalid_services, minimum_version, minimum_services, relay) ->start(handle_started); - } else { - attach(channel, own_version, own_services, invalid_services, minimum_version, minimum_services)->start(handle_started); - } -} - -void session_block_sync::handle_channel_start(code const& ec, channel::ptr channel, reservation::ptr row, result_handler handler) { - // Treat a start failure just like a completion failure. - if (ec) { - handle_channel_complete(ec, row, handler); - return; - } - - attach_protocols(channel, row, handler); -} - -void session_block_sync::attach_protocols(channel::ptr channel, reservation::ptr row, result_handler handler) { - if (channel->negotiated_version() >= version::level::bip31) { - attach(channel)->start(); - } else { - attach(channel)->start(); - } - - attach(channel)->start(); - attach(channel, row)->start(BIND3(handle_channel_complete, _1, row, handler)); -} - -void session_block_sync::handle_channel_complete(code const& ec, reservation::ptr row, result_handler handler) { - if (ec) { - // There is no failure scenario, we ignore the result code here. - new_connection(row, handler); - return; - } - - timer_->stop(); - reservations_.remove(row); - - spdlog::debug("[node] Completed block slot ({})", row->slot()); - - // This is the end of the block sync sequence. - handler(error::success); -} - -void session_block_sync::handle_channel_stop(code const& ec, reservation::ptr row) { - spdlog::info("[node] Channel stopped on block slot ({}) {}", row->slot(), ec.message()); -} - -void session_block_sync::handle_complete(code const& ec, result_handler handler) { - // Always stop but give sync priority over stop for reporting. - auto const stop = reservations_.stop(); - - if (ec) { - spdlog::debug("[node] Failed to complete block sync: {}", ec.message()); - handler(ec); - return; - } - - if ( ! stop) { - spdlog::debug("[node] Failed to reset write lock: {}", ec.message()); - handler(error::operation_failed); - return; - } - - spdlog::debug("[node] Completed block sync."); - handler(ec); -} - -// Timer. -// ---------------------------------------------------------------------------- - -// private: -void session_block_sync::reset_timer() { - if (stopped()) { - return; - } - - timer_->start(BIND1(handle_timer, _1)); -} - -void session_block_sync::handle_timer(code const& ec) { - if (stopped()) { - return; - } - - spdlog::debug("[node] Fired session_block_sync timer: {}", ec.message()); - - ////// TODO: If (total database time as a fn of total time) add a channel. - ////// TODO: push into reservations_ implementation. - ////// TODO: add a boolean increment method to the synchronizer and pass here. - ////size_t const id = reservations_.table().size(); - ////auto const row = std::make_shared(reservations_, id); - ////const synchronizer handler({}, 0, "name", true); - ////if (add) new_connection(row, handler); - ////// TODO: drop the slowest channel - //////If (drop) reservations_.prune(); - - reset_timer(); -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/sessions/session_header_sync.cpp b/src/node/src/sessions/session_header_sync.cpp deleted file mode 100644 index de8330ab..00000000 --- a/src/node/src/sessions/session_header_sync.cpp +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include -#include -#include - -namespace kth::node { - -#define CLASS session_header_sync -#define NAME "session_header_sync" - -using namespace kth::blockchain; -using namespace kth::domain::config; -using namespace kth::database; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -// The minimum rate back off factor, must be < 1.0. -static constexpr float back_off_factor = 0.75f; - -// The starting minimum header download rate, exponentially backs off. -static constexpr uint32_t headers_per_second = 10000; - -// Sort is required here but not in configuration settings. -session_header_sync::session_header_sync(full_node& network, check_list& hashes, fast_chain& blockchain, infrastructure::config::checkpoint::list const& checkpoints) - : session(network, false) - , hashes_(hashes) - , minimum_rate_(headers_per_second) - , chain_(blockchain) - , checkpoints_(infrastructure::config::checkpoint::sort(checkpoints)) - , CONSTRUCT_TRACK(session_header_sync) -{ - static_assert(back_off_factor < 1.0, "invalid back-off factor"); -} - -// Start sequence. -// ---------------------------------------------------------------------------- - -void session_header_sync::start(result_handler handler) { - session::start(CONCURRENT_DELEGATE2(handle_started, _1, handler)); -} - -void session_header_sync::handle_started(code const& ec, result_handler handler) { - if (ec) { - handler(ec); - return; - } - - // TODO: expose header count and emit here. - spdlog::info("[node] Getting headers."); - - if ( ! initialize()) { - handler(error::operation_failed); - return; - } - - auto const complete = synchronize(handler, headers_.size(), NAME); - - // This is the end of the start sequence. - for (auto const row: headers_) { - new_connection(row, complete); - } -} - -// Header sync sequence. -// ---------------------------------------------------------------------------- - -void session_header_sync::new_connection(header_list::ptr row, result_handler handler) { - if (stopped()) { - spdlog::debug("[node] Suspending header slot ({}).", row->slot()); - return; - } - - spdlog::debug("[node] Starting header slot ({}).", row->slot()); - - // HEADER SYNC CONNECT - session_batch::connect(BIND4(handle_connect, _1, _2, row, handler)); -} - -void session_header_sync::handle_connect(code const& ec, channel::ptr channel, header_list::ptr row, result_handler handler) { - if (ec) { - spdlog::debug("[node] Failure connecting header slot ({}) {}", row->slot(), ec.message()); - new_connection(row ,handler); - return; - } - - spdlog::debug("[node] Connected header slot ({}) [{}]", row->slot(), channel->authority()); - - register_channel(channel, - BIND4(handle_channel_start, _1, channel, row, handler), - BIND2(handle_channel_stop, _1, row)); -} - -void session_header_sync::attach_handshake_protocols(channel::ptr channel, result_handler handle_started) { - // Don't use configured services, relay or min version for header sync. - auto const relay = false; - auto const own_version = settings_.protocol_maximum; - auto const own_services = version::service::none; - auto const invalid_services = settings_.invalid_services; - auto const minimum_version = version::level::headers; - auto const minimum_services = version::service::node_network; - - // The negotiated_version is initialized to the configured maximum. - if (channel->negotiated_version() >= version::level::bip61) { - attach(channel, own_version, own_services, - invalid_services, minimum_version, minimum_services, relay) - ->start(handle_started); - } else { - attach(channel, own_version, own_services, - invalid_services, minimum_version, minimum_services) - ->start(handle_started); - } -} - -void session_header_sync::handle_channel_start(code const& ec, channel::ptr channel, header_list::ptr row, result_handler handler) { - // Treat a start failure just like a completion failure. - if (ec) { - handle_complete(ec, row, handler); - return; - } - - attach_protocols(channel, row, handler); -} - -void session_header_sync::attach_protocols(channel::ptr channel, header_list::ptr row, result_handler handler) { - KTH_ASSERT(channel->negotiated_version() >= version::level::headers); - - if (channel->negotiated_version() >= version::level::bip31) { - attach(channel)->start(); - } else { - attach(channel)->start(); - } - - attach(channel)->start(); - attach(channel, row, minimum_rate_)->start(BIND3(handle_complete, _1, row, handler)); -} - -void session_header_sync::handle_complete(code const& ec, header_list::ptr row, result_handler handler) { - if (ec) { - // Reduce the rate minimum so that we don't get hung up. - minimum_rate_ = uint32_t(minimum_rate_ * back_off_factor); - - // There is no failure scenario, we ignore the result code here. - new_connection(row, handler); - return; - } - - //************************************************************************* - // TODO: as each header sink slot completes store headers to database and - // assign its checkpoints to hashes_, terminating the slot. - //************************************************************************* - - auto height = row->first_height(); - auto const& headers = row->headers(); - - // Store the hash if there is a gap reservation. - for (auto const& header: headers) { - hashes_.enqueue(header.hash(), height++); - } - - spdlog::debug("[node] Completed header slot ({})", row->slot()); - - // This is the end of the header sync sequence. - handler(error::success); -} - -void session_header_sync::handle_channel_stop(code const& ec, header_list::ptr row) { - spdlog::debug("[node] Channel stopped on header slot ({}) {}", row->slot(), ec.message()); -} - -// Utility. -// ---------------------------------------------------------------------------- - -bool session_header_sync::initialize() { - if ( ! hashes_.empty()) { - spdlog::error("[node] Block hash list must not be initialized."); - return false; - } - //************************************************************************* - // TODO: get top and pair up checkpoints into slots. - auto const& front = checkpoints_.front(); - auto const& back = checkpoints_.back(); - headers_.push_back(std::make_shared(0, front, back)); - //************************************************************************* - - return true; -} - -} // namespace kth::node \ No newline at end of file diff --git a/src/node/src/sessions/session_inbound.cpp b/src/node/src/sessions/session_inbound.cpp deleted file mode 100644 index 003b3738..00000000 --- a/src/node/src/sessions/session_inbound.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -namespace kth::node { - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -session_inbound::session_inbound(full_node& network, safe_chain& chain) - : session(network, true) - , chain_(chain) - , CONSTRUCT_TRACK(node::session_inbound) -{ - spdlog::info("[node] Starting inbound session on port ({}).", network.network_settings().inbound_port); -} - -void session_inbound::attach_protocols(channel::ptr channel) { - auto const version = channel->negotiated_version(); - - if (version >= version::level::bip31) { - attach(channel)->start(); - } else { - attach(channel)->start(); - } - - if (version >= domain::message::version::level::bip61) { - attach(channel)->start(); - } - - attach(channel)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); -} - -} // namespace kth::node diff --git a/src/node/src/sessions/session_manual.cpp b/src/node/src/sessions/session_manual.cpp deleted file mode 100644 index 06fb56f7..00000000 --- a/src/node/src/sessions/session_manual.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -namespace kth::node { - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -session_manual::session_manual(full_node& network, safe_chain& chain) - : session(network, true) - , chain_(chain) - , CONSTRUCT_TRACK(node::session_manual) -{} - -void session_manual::attach_protocols(channel::ptr channel) { - auto const version = channel->negotiated_version(); - - if (version >= version::level::bip31) { - attach(channel)->start(); - } else { - attach(channel)->start(); - } - - if (version >= domain::message::version::level::bip61) { - attach(channel)->start(); - } - - attach(channel)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); -} - -} // namespace kth::node diff --git a/src/node/src/sessions/session_outbound.cpp b/src/node/src/sessions/session_outbound.cpp deleted file mode 100644 index 42fd95e0..00000000 --- a/src/node/src/sessions/session_outbound.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#if ! defined(__EMSCRIPTEN__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -namespace kth::node { - -using namespace kth::blockchain; -using namespace kth::domain::message; -using namespace kth::network; -using namespace std::placeholders; - -session_outbound::session_outbound(full_node& network, safe_chain& chain) - : session(network, true) - , chain_(chain) - , CONSTRUCT_TRACK(node::session_outbound) -{} - -void session_outbound::attach_protocols(channel::ptr channel) { - auto const version = channel->negotiated_version(); - - if (version >= version::level::bip31) { - attach(channel)->start(); - } else { - attach(channel)->start(); - } - - if (version >= domain::message::version::level::bip61) { - attach(channel)->start(); - } - - attach(channel)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); - attach(channel, chain_)->start(); -} - -} // namespace kth::node diff --git a/src/node/src/sync_session.cpp b/src/node/src/sync_session.cpp new file mode 100644 index 00000000..93acc8b6 --- /dev/null +++ b/src/node/src/sync_session.cpp @@ -0,0 +1,513 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace kth::node { + +using namespace kth::blockchain; +using namespace kth::network; + +// ============================================================================= +// Construction +// ============================================================================= + +sync_session::sync_session( + block_chain& chain, + peer_session::ptr peer, + domain::config::network network, + sync_config const& config) + : chain_(chain) + , organizer_(chain, chain.chain_settings(), network) + , peer_(std::move(peer)) + , config_(config) +{ + // Get current chain heights (header-sync and block-sync) + auto const heights = chain_.get_last_heights(); + if (heights) { + header_height_ = heights->first; // header-sync height + block_height_ = heights->second; // block-sync height + } + + // Get target height from peer's version message + auto peer_version = peer_->peer_version(); + if (peer_version) { + target_height_ = peer_version->start_height(); + } + + // Get hash of current header tip (for getheaders locator) + if (header_height_ > 0) { + auto const hash = chain_.get_block_hash(header_height_); + if (hash) { + last_header_hash_ = *hash; + } + } else { + // Genesis block hash + auto const genesis_header = chain_.get_header(0); + if (genesis_header) { + last_header_hash_ = genesis_header->hash(); + } + } +} + +sync_session::ptr make_sync_session( + block_chain& chain, + peer_session::ptr peer, + domain::config::network network, + sync_config const& config) +{ + return std::make_shared(chain, peer, network, config); +} + +// ============================================================================= +// Run +// ============================================================================= + +::asio::awaitable sync_session::run() { + sync_result result{}; + + spdlog::info("[sync] Starting headers-first sync with [{}], header-sync: {}, block-sync: {}", + peer_->authority(), header_height_, block_height_); + + // Check peer version supports headers-first + if (peer_->negotiated_version() < config_.minimum_version) { + spdlog::warn("[sync] Peer [{}] version {} too low for headers-first sync", + peer_->authority(), peer_->negotiated_version()); + result.error = error::channel_stopped; + co_return result; + } + + // ========================================================================== + // PHASE 1: Sync ALL headers first + // ========================================================================== + + auto const headers_to_sync = target_height_ > header_height_ + ? target_height_ - header_height_ : 0; + + if (headers_to_sync > 0) { + spdlog::info("[sync] Phase 1: Syncing headers from [{}], target height {}, need ~{} headers", + peer_->authority(), target_height_, headers_to_sync); + + // Log memory allocator info + if (kth::is_jemalloc_active()) { + spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); + } else { + spdlog::info("[sync] Memory allocator: system default"); + } + + // Log system memory info + auto const total_mem = kth::get_total_system_memory(); + auto const available_mem = kth::get_available_system_memory(); + spdlog::info("[sync] System memory: total {} MB, available {} MB", + total_mem / (1024 * 1024), available_mem / (1024 * 1024)); + + // Initialize organizer with current state and expected headers + organizer_.start(); + organizer_.initialize(header_height_, last_header_hash_, headers_to_sync); + + auto const optimal_cache = organizer_.calculate_optimal_cache_size(headers_to_sync); + spdlog::info("[sync] Header cache: optimal size {} headers", optimal_cache); + + // Measure memory before sync + auto const mem_before = kth::get_resident_memory(); + spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); + + auto const start_time = std::chrono::steady_clock::now(); + + // Sync headers until complete + while (!peer_->stopped() && !synced_) { + auto ec = co_await sync_headers_batch(); + if (ec) { + if (ec == error::channel_timeout) { + spdlog::debug("[sync] Headers timeout from [{}], retrying...", + peer_->authority()); + continue; + } + result.error = ec; + co_return result; + } + + // Log progress every 10000 headers + if (total_headers_ % 10000 == 0 && total_headers_ > 0) { + auto const elapsed = std::chrono::steady_clock::now() - start_time; + auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); + auto const headers_per_sec = elapsed_secs > 0 ? total_headers_ / elapsed_secs : 0; + + auto const current_synced_height = header_height_ + total_headers_; + auto const hash_str = encode_hash(last_header_hash_); + + if (target_height_ > 0) { + auto const percent = (current_synced_height * 100) / target_height_; + auto const remaining = headers_to_sync > total_headers_ ? headers_to_sync - total_headers_ : 0; + auto const eta_secs = headers_per_sec > 0 ? remaining / headers_per_sec : 0; + + spdlog::info("[sync] Headers: {:>7}/{} ({:>2}%), {:>6}/s, ETA {:>3}s, cache: {} headers", + current_synced_height, target_height_, percent, + headers_per_sec, eta_secs, + organizer_.cache_size()); + } else { + spdlog::info("[sync] Headers: {:>7}, {:>6}/s, cache: {} headers", + current_synced_height, headers_per_sec, + organizer_.cache_size()); + } + } + } + + // Measure memory after headers received + auto const mem_after_headers = kth::get_resident_memory(); + auto const bytes_per_header = total_headers_ > 0 + ? (mem_after_headers - mem_before) / total_headers_ : 0; + spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", + total_headers_, mem_after_headers / (1024 * 1024), + (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); + + // Flush remaining headers to database + if (organizer_.has_pending()) { + spdlog::info("[sync] Flushing {} cached headers to database...", + organizer_.cache_size()); + auto const db_start = std::chrono::steady_clock::now(); + + auto const flush_ec = organizer_.flush(); + if (flush_ec && flush_ec != error::duplicate_block) { + spdlog::warn("[sync] Failed to flush headers: {}", flush_ec.message()); + result.error = flush_ec; + co_return result; + } + + auto const db_elapsed = std::chrono::steady_clock::now() - db_start; + auto const db_ms = std::chrono::duration_cast(db_elapsed).count(); + spdlog::info("[sync] Headers flush completed in {}ms", db_ms); + } + + auto const final_header_height = organizer_.header_height(); + spdlog::info("[sync] Phase 1 complete: synced to height {} ({} new headers) from [{}]", + final_header_height, total_headers_, peer_->authority()); + + // Clean up organizer + organizer_.clear_cache(); + organizer_.stop(); + + } else { + spdlog::info("[sync] Phase 1: Headers already synced to height {}", header_height_); + } + + // ========================================================================== + // PHASE 2: Download blocks + // ========================================================================== + + auto const current_header_height = header_height_ + total_headers_; + if (block_height_ < current_header_height) { + // We need to download blocks - get hashes from DB + std::vector block_hashes; + + if (block_height_ < current_header_height) { + auto const blocks_to_download = current_header_height - block_height_; + spdlog::info("[sync] Loading {} block hashes from database...", blocks_to_download); + + block_hashes.reserve(blocks_to_download); + for (size_t h = block_height_ + 1; h <= current_header_height; ++h) { + auto const hash = chain_.get_block_hash(h); + if (hash) { + block_hashes.push_back(*hash); + } + } + } + + if (!block_hashes.empty()) { + spdlog::info("[sync] Phase 2: Downloading blocks {}-{} ({} blocks) from [{}]", + block_height_ + 1, block_height_ + block_hashes.size(), + block_hashes.size(), peer_->authority()); + + auto ec = co_await sync_blocks(block_hashes); + if (ec) { + result.error = ec; + co_return result; + } + } + } + + result.headers_received = total_headers_; + result.blocks_received = total_blocks_; + result.final_height = block_height_; + + spdlog::info("[sync] Sync complete with [{}], height {} ({} headers, {} blocks)", + peer_->authority(), block_height_, total_headers_, total_blocks_); + + co_return result; +} + +// ============================================================================= +// Headers Sync +// ============================================================================= + +::asio::awaitable sync_session::sync_headers_batch() { + // Build locator from current chain state + auto locator = build_locator(); + + spdlog::debug("[sync] Requesting headers from [{}] with {} locator hashes", + peer_->authority(), locator.size()); + + // Request headers + auto headers_result = co_await request_headers( + *peer_, locator, null_hash, config_.headers_timeout); + + if (!headers_result) { + spdlog::debug("[sync] Failed to get headers from [{}]: {}", + peer_->authority(), headers_result.error().message()); + co_return headers_result.error(); + } + + auto const& headers = *headers_result; + auto const count = headers.elements().size(); + + spdlog::debug("[sync] Received {} headers from [{}]", + count, peer_->authority()); + + // Empty response means we're synced + if (count == 0) { + spdlog::info("[sync] Peer returned 0 headers - marking as synced"); + synced_ = true; + co_return error::success; + } + + // Add headers to organizer (validates and caches) + auto const add_result = organizer_.add_headers(headers.elements()); + if (add_result.error) { + spdlog::warn("[sync] Invalid headers from [{}]: {}", + peer_->authority(), add_result.error.message()); + co_return add_result.error; + } + + // Update tracking state + total_headers_ += add_result.headers_added; + last_header_hash_ = organizer_.header_tip_hash(); + + spdlog::debug("[sync] Added {} headers, cache now {} headers ({} MB)", + add_result.headers_added, add_result.cache_size, + add_result.cache_memory_bytes / (1024 * 1024)); + + // If we got fewer than max headers (2000), peer has no more + if (count < config_.max_headers_per_request) { + synced_ = true; + spdlog::info("[sync] Headers sync complete: received {} < {} (max batch) - total: {}", + count, config_.max_headers_per_request, total_headers_); + } + + co_return error::success; +} + +// ============================================================================= +// Blocks Sync +// ============================================================================= + +::asio::awaitable sync_session::sync_blocks( + std::vector const& hashes) +{ + auto const total_to_download = hashes.size(); + auto const start_height = block_height_; + auto const target_height = start_height + total_to_download; + + spdlog::info("[sync] Starting block download: blocks {}-{} ({} blocks) from [{}]", + start_height + 1, target_height, total_to_download, peer_->authority()); + + auto const start_time = std::chrono::steady_clock::now(); + + // Request blocks in batches + for (size_t i = 0; i < hashes.size(); i += config_.max_blocks_per_request) { + auto const batch_end = std::min(i + config_.max_blocks_per_request, hashes.size()); + + for (size_t j = i; j < batch_end; ++j) { + auto block_result = co_await request_block( + *peer_, hashes[j], config_.block_timeout); + + if (!block_result) { + spdlog::debug("[sync] Failed to get block {} from [{}]: {}", + encode_hash(hashes[j]), peer_->authority(), + block_result.error().message()); + co_return block_result.error(); + } + + auto block_ptr = std::make_shared( + std::move(*block_result)); + + spdlog::debug("[sync] Organizing block {} at height {}", + encode_hash(hashes[j]).substr(0, 16), block_height_ + 1); + + auto ec = co_await chain_.organize(block_ptr); + + if (ec && ec != error::duplicate_block) { + spdlog::warn("[sync] Block organize failed for {} from [{}]: {}", + encode_hash(hashes[j]), peer_->authority(), ec.message()); + } + + ++block_height_; + ++total_blocks_; + + // Log progress every 1000 blocks + if (total_blocks_ % 1000 == 0) { + auto const elapsed = std::chrono::steady_clock::now() - start_time; + auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); + auto const blocks_per_sec = elapsed_secs > 0 ? total_blocks_ / elapsed_secs : 0; + auto const remaining = total_to_download - total_blocks_; + auto const eta_secs = blocks_per_sec > 0 ? remaining / blocks_per_sec : 0; + + spdlog::info("[sync] Blocks: {}/{} ({}%), height {}, {}/s, ETA {}s", + total_blocks_, total_to_download, + (total_blocks_ * 100) / total_to_download, + block_height_, + blocks_per_sec, + eta_secs); + } + } + } + + auto const elapsed = std::chrono::steady_clock::now() - start_time; + auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); + spdlog::info("[sync] Block download complete: {} blocks in {}s ({}/s)", + total_blocks_, elapsed_secs, + elapsed_secs > 0 ? total_blocks_ / elapsed_secs : total_blocks_); + + co_return error::success; +} + +// ============================================================================= +// Locator Building +// ============================================================================= + +hash_list sync_session::build_locator() const { + hash_list locator; + + // Start with the tip (from organizer if we have cached headers) + auto const tip_hash = organizer_.header_tip_hash(); + if (tip_hash != null_hash) { + locator.push_back(tip_hash); + } else if (last_header_hash_ != null_hash) { + locator.push_back(last_header_hash_); + } + + // Add exponentially spaced hashes going back + size_t step = 1; + size_t height = header_height_ + total_headers_; + + while (height > 0) { + if (height <= step) { + height = 0; + } else { + height -= step; + } + + auto const hash = chain_.get_block_hash(height); + if (hash) { + locator.push_back(*hash); + } + + if (locator.size() >= 10) { + step *= 2; + } + + if (locator.size() >= 64) { + break; + } + } + + // Always include genesis + if (height > 0) { + auto const genesis_hash = chain_.get_block_hash(0); + if (genesis_hash) { + locator.push_back(*genesis_hash); + } + } + + return locator; +} + +// ============================================================================= +// Properties +// ============================================================================= + +bool sync_session::is_synced() const { + return synced_; +} + +std::pair sync_session::current_heights() const { + return {organizer_.header_height(), block_height_}; +} + +// ============================================================================= +// Utility Functions +// ============================================================================= + +::asio::awaitable sync_from_best_peer( + block_chain& chain, + p2p_node& p2p, + domain::config::network network, + sync_config const& config) +{ + sync_result result{}; + + // Get current chain heights + size_t our_block_height = 0; + auto const heights = chain.get_last_heights(); + if (heights) { + our_block_height = heights->second; + } + + // Get all connected peers + auto peers = co_await p2p.peers().all(); + + if (peers.empty()) { + spdlog::warn("[sync] No peers available for sync"); + result.error = error::channel_stopped; + co_return result; + } + + spdlog::info("[sync] Selecting sync peer from {} connected peers, our height: {}", + peers.size(), our_block_height); + + // Find peer with highest start_height that's ahead of us + peer_session::ptr best_peer; + uint32_t best_height = 0; + + for (auto const& peer : peers) { + auto version = peer->peer_version(); + if (!version) { + continue; + } + + auto const peer_height = version->start_height(); + + if (peer_height <= our_block_height) { + continue; + } + + if (peer_height > best_height) { + best_height = peer_height; + best_peer = peer; + } + } + + if (!best_peer) { + spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_block_height); + result.error = error::success; + result.final_height = our_block_height; + co_return result; + } + + spdlog::info("[sync] Selected peer [{}] with height {} for sync", + best_peer->authority(), best_height); + + auto session = make_sync_session(chain, best_peer, network, config); + co_return co_await session->run(); +} + +} // namespace kth::node diff --git a/src/node/src/utility/reservations.cpp b/src/node/src/utility/reservations.cpp index d3deaf57..36d699a6 100644 --- a/src/node/src/utility/reservations.cpp +++ b/src/node/src/utility/reservations.cpp @@ -22,7 +22,7 @@ namespace kth::node { using namespace kth::blockchain; using namespace kth::domain::chain; -reservations::reservations(check_list& hashes, fast_chain& chain, settings const& settings) +reservations::reservations(check_list& hashes, block_chain& chain, settings const& settings) : hashes_(hashes) , max_request_(max_get_data) , timeout_(settings.sync_timeout_seconds) diff --git a/src/node/test/utility.hpp b/src/node/test/utility.hpp index 6e405145..17042a11 100644 --- a/src/node/test/utility.hpp +++ b/src/node/test/utility.hpp @@ -42,7 +42,7 @@ class reservation_fixture : public reservation { clock::time_point now_; }; -class blockchain_fixture : public blockchain::fast_chain { +class blockchain_fixture { public: blockchain_fixture(bool import_result=true, size_t gap_trigger=max_size_t, size_t gap_height=max_size_t); From 37a9d554d11d35397314e9a425d574992ac22b4c Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Fri, 19 Dec 2025 13:52:05 +0100 Subject: [PATCH 08/14] fix: transition from header sync to block sync (Phase 2) (#156) - Get block hashes from header_index instead of database - Headers are stored in memory during IBD, not persisted to DB yet - Enables proper Phase 1 -> Phase 2 transition after header sync completes --- src/node/src/sync_session.cpp | 722 +++++++++++++++++++++++++++------- 1 file changed, 579 insertions(+), 143 deletions(-) diff --git a/src/node/src/sync_session.cpp b/src/node/src/sync_session.cpp index 93acc8b6..884efb1d 100644 --- a/src/node/src/sync_session.cpp +++ b/src/node/src/sync_session.cpp @@ -7,17 +7,33 @@ #include #include +#include #include +#include #include +#include #include #include +#include +#include namespace kth::node { using namespace kth::blockchain; using namespace kth::network; +// "Permanent" ban duration - 10 years in seconds +// Using a large but safe value instead of hours::max() to avoid overflow +constexpr auto permanent_ban_duration = std::chrono::seconds(10 * 365 * 24 * 60 * 60); + +// Forward declaration - defined at end of file +static ::asio::awaitable persist_headers_background( + block_chain& chain, + header_index const& index, + size_t start_height, + size_t end_height); + // ============================================================================= // Construction // ============================================================================= @@ -26,10 +42,13 @@ sync_session::sync_session( block_chain& chain, peer_session::ptr peer, domain::config::network network, - sync_config const& config) + sync_config const& config, + size_t target_height, + p2p_node* p2p_node) : chain_(chain) - , organizer_(chain, chain.chain_settings(), network) + , organizer_(chain.headers(), chain.chain_settings(), network) , peer_(std::move(peer)) + , p2p_node_(p2p_node) , config_(config) { // Get current chain heights (header-sync and block-sync) @@ -39,23 +58,28 @@ sync_session::sync_session( block_height_ = heights->second; // block-sync height } - // Get target height from peer's version message - auto peer_version = peer_->peer_version(); - if (peer_version) { - target_height_ = peer_version->start_height(); + // Use provided target height if given, otherwise use peer's start_height + if (target_height > 0) { + target_height_ = target_height; + } else { + auto peer_version = peer_->peer_version(); + if (peer_version) { + target_height_ = peer_version->start_height(); + } } // Get hash of current header tip (for getheaders locator) if (header_height_ > 0) { + // TODO(fernando): resuming sync - headers in DB need to be loaded into header_index auto const hash = chain_.get_block_hash(header_height_); if (hash) { last_header_hash_ = *hash; } } else { - // Genesis block hash - auto const genesis_header = chain_.get_header(0); - if (genesis_header) { - last_header_hash_ = genesis_header->hash(); + // Fresh start - get genesis hash + auto const genesis = chain_.get_header(0); + if (genesis) { + last_header_hash_ = genesis->hash(); } } } @@ -64,9 +88,11 @@ sync_session::ptr make_sync_session( block_chain& chain, peer_session::ptr peer, domain::config::network network, - sync_config const& config) + sync_config const& config, + size_t target_height, + p2p_node* p2p_node) { - return std::make_shared(chain, peer, network, config); + return std::make_shared(chain, peer, network, config, target_height, p2p_node); } // ============================================================================= @@ -77,7 +103,7 @@ ::asio::awaitable sync_session::run() { sync_result result{}; spdlog::info("[sync] Starting headers-first sync with [{}], header-sync: {}, block-sync: {}", - peer_->authority(), header_height_, block_height_); + peer_->authority_with_agent(), header_height_, block_height_); // Check peer version supports headers-first if (peer_->negotiated_version() < config_.minimum_version) { @@ -91,110 +117,155 @@ ::asio::awaitable sync_session::run() { // PHASE 1: Sync ALL headers first // ========================================================================== - auto const headers_to_sync = target_height_ > header_height_ - ? target_height_ - header_height_ : 0; + // Sync organizer tip from header_index FIRST (may have headers from previous peer) + organizer_.start(); + organizer_.sync_tip(); + + // Use organizer's height (from shared header_index) instead of DB height + auto const current_header_height = organizer_.header_height(); + auto const headers_to_sync = target_height_ > uint32_t(current_header_height) + ? target_height_ - current_header_height : 0; if (headers_to_sync > 0) { - spdlog::info("[sync] Phase 1: Syncing headers from [{}], target height {}, need ~{} headers", - peer_->authority(), target_height_, headers_to_sync); + spdlog::info("[sync] Phase 1: Syncing headers from [{}], target height {}, current {}, need ~{} headers", + peer_->authority(), target_height_, current_header_height, headers_to_sync); - // Log memory allocator info - if (kth::is_jemalloc_active()) { - spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); - } else { - spdlog::info("[sync] Memory allocator: system default"); - } + // // Log memory allocator info + // if (kth::is_jemalloc_active()) { + // spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); + // } else { + // spdlog::info("[sync] Memory allocator: system default"); + // } // Log system memory info - auto const total_mem = kth::get_total_system_memory(); - auto const available_mem = kth::get_available_system_memory(); - spdlog::info("[sync] System memory: total {} MB, available {} MB", - total_mem / (1024 * 1024), available_mem / (1024 * 1024)); - - // Initialize organizer with current state and expected headers - organizer_.start(); - organizer_.initialize(header_height_, last_header_hash_, headers_to_sync); - - auto const optimal_cache = organizer_.calculate_optimal_cache_size(headers_to_sync); - spdlog::info("[sync] Header cache: optimal size {} headers", optimal_cache); + // auto const total_mem = kth::get_total_system_memory(); + // auto const available_mem = kth::get_available_system_memory(); + // spdlog::info("[sync] System memory: total {} MB, available {} MB", + // total_mem / (1024 * 1024), available_mem / (1024 * 1024)); + + // BCHN-style: Calculate headers sync deadline + // Timeout = base + per_header * expected_headers + headers_sync_start_ = clock::now(); + auto const timeout_duration = config_.headers_download_timeout_base + + std::chrono::duration_cast( + config_.headers_download_timeout_per_header * headers_to_sync); + headers_sync_deadline_ = headers_sync_start_ + timeout_duration; + + auto const timeout_secs = std::chrono::duration_cast(timeout_duration).count(); + spdlog::info("[sync] Headers sync timeout: {}s (base: {}s + {}us/header * {} headers)", + timeout_secs, + config_.headers_download_timeout_base.count(), + config_.headers_download_timeout_per_header.count(), + headers_to_sync); + + // TODO(fernando): calculate optimal cache size based on available memory + // auto const optimal_cache = organizer_.calculate_optimal_cache_size(headers_to_sync); + // spdlog::info("[sync] Header cache: optimal size {} headers", optimal_cache); // Measure memory before sync - auto const mem_before = kth::get_resident_memory(); - spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); + // auto const mem_before = kth::get_resident_memory(); + // spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); auto const start_time = std::chrono::steady_clock::now(); + int consecutive_timeouts = 0; + constexpr int max_consecutive_timeouts = 3; // Sync headers until complete while (!peer_->stopped() && !synced_) { + // BCHN-style: Check if we've exceeded the headers sync deadline + if (clock::now() > headers_sync_deadline_) { + auto const elapsed = std::chrono::duration_cast( + clock::now() - headers_sync_start_).count(); + spdlog::warn("[sync] Headers sync timeout after {}s from [{}], " + "received {} headers (peer too slow)", + elapsed, peer_->authority(), total_headers_); + headers_sync_timed_out_ = true; + result.error = error::channel_timeout; + result.timed_out = true; + co_return result; + } + auto ec = co_await sync_headers_batch(); if (ec) { if (ec == error::channel_timeout) { - spdlog::debug("[sync] Headers timeout from [{}], retrying...", - peer_->authority()); + ++consecutive_timeouts; + if (consecutive_timeouts >= max_consecutive_timeouts) { + spdlog::warn("[sync] {} consecutive batch timeouts from [{}], giving up on this peer", + consecutive_timeouts, peer_->authority()); + result.error = error::channel_timeout; + result.timed_out = true; + co_return result; + } + spdlog::debug("[sync] Headers batch timeout from [{}], retrying ({}/{})...", + peer_->authority(), consecutive_timeouts, max_consecutive_timeouts); continue; } result.error = ec; co_return result; } + // Reset timeout counter on success + consecutive_timeouts = 0; + // Log progress every 10000 headers if (total_headers_ % 10000 == 0 && total_headers_ > 0) { auto const elapsed = std::chrono::steady_clock::now() - start_time; auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); auto const headers_per_sec = elapsed_secs > 0 ? total_headers_ / elapsed_secs : 0; - auto const current_synced_height = header_height_ + total_headers_; - auto const hash_str = encode_hash(last_header_hash_); + // Use organizer's current height (includes headers from previous peers) + auto const current_synced_height = organizer_.header_height(); if (target_height_ > 0) { - auto const percent = (current_synced_height * 100) / target_height_; + auto const percent = (uint32_t(current_synced_height) * 100) / target_height_; auto const remaining = headers_to_sync > total_headers_ ? headers_to_sync - total_headers_ : 0; auto const eta_secs = headers_per_sec > 0 ? remaining / headers_per_sec : 0; - spdlog::info("[sync] Headers: {:>7}/{} ({:>2}%), {:>6}/s, ETA {:>3}s, cache: {} headers", + spdlog::info("[sync] {:>7}/{} ({:>2}%), {:>6}/s, ETA {:>3}s", current_synced_height, target_height_, percent, - headers_per_sec, eta_secs, - organizer_.cache_size()); + headers_per_sec, eta_secs); + +#ifdef KTH_WITH_STATS + // Print detailed stats when enabled + auto const& stats = global_sync_stats(); + auto const batch_cnt = stats.batch_count.load(std::memory_order_relaxed); + if (batch_cnt > 0) { + auto const loc_ms = stats.batch_locator_ns.load() / 1000000 / batch_cnt; + auto const net_ms = stats.batch_network_ns.load() / 1000000 / batch_cnt; + auto const proc_ms = stats.batch_process_ns.load() / 1000000 / batch_cnt; + spdlog::info("[stats] loc:{}ms net:{}ms proc:{}ms/batch", loc_ms, net_ms, proc_ms); + } +#endif } else { - spdlog::info("[sync] Headers: {:>7}, {:>6}/s, cache: {} headers", + spdlog::info("[sync] {:>7}, {:>6}/s, index: {} headers", current_synced_height, headers_per_sec, - organizer_.cache_size()); + organizer_.size()); } } } // Measure memory after headers received - auto const mem_after_headers = kth::get_resident_memory(); - auto const bytes_per_header = total_headers_ > 0 - ? (mem_after_headers - mem_before) / total_headers_ : 0; - spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", - total_headers_, mem_after_headers / (1024 * 1024), - (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); - - // Flush remaining headers to database - if (organizer_.has_pending()) { - spdlog::info("[sync] Flushing {} cached headers to database...", - organizer_.cache_size()); - auto const db_start = std::chrono::steady_clock::now(); - - auto const flush_ec = organizer_.flush(); - if (flush_ec && flush_ec != error::duplicate_block) { - spdlog::warn("[sync] Failed to flush headers: {}", flush_ec.message()); - result.error = flush_ec; - co_return result; - } + // auto const mem_after_headers = kth::get_resident_memory(); + // auto const bytes_per_header = total_headers_ > 0 + // ? (mem_after_headers - mem_before) / total_headers_ : 0; + // spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", + // total_headers_, mem_after_headers / (1024 * 1024), + // (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); - auto const db_elapsed = std::chrono::steady_clock::now() - db_start; - auto const db_ms = std::chrono::duration_cast(db_elapsed).count(); - spdlog::info("[sync] Headers flush completed in {}ms", db_ms); - } + // NOTE: Header persistence to DB now happens in Phase 2 as a background task + // This allows block sync to proceed immediately while headers are saved auto const final_header_height = organizer_.header_height(); + + // Check why header sync ended + if (!synced_ && peer_->stopped()) { + spdlog::warn("[sync] Header sync peer disconnected at height {} (target was {})", + final_header_height, target_height_); + } + spdlog::info("[sync] Phase 1 complete: synced to height {} ({} new headers) from [{}]", final_header_height, total_headers_, peer_->authority()); - // Clean up organizer - organizer_.clear_cache(); organizer_.stop(); } else { @@ -202,31 +273,87 @@ ::asio::awaitable sync_session::run() { } // ========================================================================== - // PHASE 2: Download blocks + // PHASE 2: Download blocks (with parallel header persistence) // ========================================================================== - auto const current_header_height = header_height_ + total_headers_; - if (block_height_ < current_header_height) { - // We need to download blocks - get hashes from DB - std::vector block_hashes; + auto const final_header_height = organizer_.header_height(); + + // Spawn background task to persist headers to database + // This runs in parallel with block sync - headers are in memory for block validation + // but also being written to DB so restart won't require re-syncing headers + { + // Get current DB header height to determine what needs persisting + auto const db_heights = chain_.get_last_heights(); + size_t db_header_height = db_heights ? db_heights->first : 0; + + // Only persist if we have new headers beyond what's in DB + if (final_header_height > 0 && size_t(final_header_height) > db_header_height) { + auto executor = co_await ::asio::this_coro::executor; + + // Spawn persist task in background (detached) + // Uses references to chain_ and index which outlive sync_session + ::asio::co_spawn(executor, + persist_headers_background( + chain_, + organizer_.index(), + db_header_height + 1, + static_cast(final_header_height)), + ::asio::detached); + } + } + + if (block_height_ < final_header_height) { + auto const blocks_to_download = final_header_height - block_height_; + spdlog::info("[sync] Phase 2: Need to download {} blocks ({} to {})", + blocks_to_download, block_height_ + 1, final_header_height); + + // Use parallel block sync if p2p_node is available + if (p2p_node_ != nullptr) { + spdlog::info("[sync] Phase 2: Using parallel block download from multiple peers"); + + // Convert sync_config to parallel_download_config_v2 (lock-free coordinator) + parallel_download_config_v2 parallel_config{ + .chunk_size = 16, // Blocks per chunk (Bitcoin protocol limit) + .slots_multiplier = 100, // slots_per_round = max_peers * 100 + .max_peers = 8, + .stall_timeout = std::chrono::seconds(config_.block_stalling_timeout), + .timeout_check_interval = std::chrono::seconds(5) + }; + + auto parallel_result = co_await parallel_block_sync_v2( + chain_, + organizer_, + *p2p_node_, + static_cast(block_height_ + 1), + static_cast(final_header_height), + parallel_config); + + if (parallel_result.error) { + spdlog::error("[sync] Parallel block sync failed: {}", + parallel_result.error.message()); + result.error = parallel_result.error; + co_return result; + } - if (block_height_ < current_header_height) { - auto const blocks_to_download = current_header_height - block_height_; - spdlog::info("[sync] Loading {} block hashes from database...", blocks_to_download); + total_blocks_ = parallel_result.blocks_validated; + block_height_ = parallel_result.final_height; + spdlog::info("[sync] Phase 2 complete: {} blocks validated via parallel sync", + parallel_result.blocks_validated); + + } else { + // Fallback to sequential download from single peer + spdlog::info("[sync] Phase 2: Using sequential block download from [{}]", + peer_->authority()); + + std::vector block_hashes; block_hashes.reserve(blocks_to_download); - for (size_t h = block_height_ + 1; h <= current_header_height; ++h) { - auto const hash = chain_.get_block_hash(h); - if (hash) { - block_hashes.push_back(*hash); - } - } - } - if (!block_hashes.empty()) { - spdlog::info("[sync] Phase 2: Downloading blocks {}-{} ({} blocks) from [{}]", - block_height_ + 1, block_height_ + block_hashes.size(), - block_hashes.size(), peer_->authority()); + // During IBD, headers are added in order, so index == height for main chain + auto& idx = organizer_.index(); + for (size_t h = block_height_ + 1; h <= size_t(final_header_height); ++h) { + block_hashes.push_back(idx.get_hash(h)); + } auto ec = co_await sync_blocks(block_hashes); if (ec) { @@ -252,14 +379,18 @@ ::asio::awaitable sync_session::run() { ::asio::awaitable sync_session::sync_headers_batch() { // Build locator from current chain state + KTH_STATS_TIME_START(locator); auto locator = build_locator(); + KTH_STATS_TIME_ADD(global_sync_stats(), locator, batch_locator_ns); spdlog::debug("[sync] Requesting headers from [{}] with {} locator hashes", peer_->authority(), locator.size()); // Request headers + KTH_STATS_TIME_START(network); auto headers_result = co_await request_headers( *peer_, locator, null_hash, config_.headers_timeout); + KTH_STATS_TIME_ADD(global_sync_stats(), network, batch_network_ns); if (!headers_result) { spdlog::debug("[sync] Failed to get headers from [{}]: {}", @@ -281,7 +412,13 @@ ::asio::awaitable sync_session::sync_headers_batch() { } // Add headers to organizer (validates and caches) + KTH_STATS_TIME_START(process); auto const add_result = organizer_.add_headers(headers.elements()); + KTH_STATS_TIME_ADD(global_sync_stats(), process, batch_process_ns); + + // Increment batch count once per successful batch + KTH_STATS_INCREMENT(global_sync_stats(), batch_count); + if (add_result.error) { spdlog::warn("[sync] Invalid headers from [{}]: {}", peer_->authority(), add_result.error.message()); @@ -292,9 +429,9 @@ ::asio::awaitable sync_session::sync_headers_batch() { total_headers_ += add_result.headers_added; last_header_hash_ = organizer_.header_tip_hash(); - spdlog::debug("[sync] Added {} headers, cache now {} headers ({} MB)", - add_result.headers_added, add_result.cache_size, - add_result.cache_memory_bytes / (1024 * 1024)); + spdlog::debug("[sync] Added {} headers, index now {} headers ({} MB)", + add_result.headers_added, add_result.index_size, + add_result.index_memory_bytes / (1024 * 1024)); // If we got fewer than max headers (2000), peer has no more if (count < config_.max_headers_per_request) { @@ -387,44 +524,52 @@ ::asio::awaitable sync_session::sync_blocks( hash_list sync_session::build_locator() const { hash_list locator; - // Start with the tip (from organizer if we have cached headers) - auto const tip_hash = organizer_.header_tip_hash(); - if (tip_hash != null_hash) { - locator.push_back(tip_hash); - } else if (last_header_hash_ != null_hash) { - locator.push_back(last_header_hash_); + // Use header_index for headers we've synced (much faster than DB) + auto const& index = organizer_.index(); + auto const tip_idx = organizer_.tip_index(); + + if (tip_idx == blockchain::header_index::null_index) { + // No headers synced yet, just use genesis from DB + auto const genesis_hash = chain_.get_block_hash(0); + if (genesis_hash) { + locator.push_back(*genesis_hash); + } + return locator; } - // Add exponentially spaced hashes going back + // Start with tip + locator.push_back(index.get_hash(tip_idx)); + + // Use skip pointers for O(log n) traversal to build exponentially-spaced locator size_t step = 1; - size_t height = header_height_ + total_headers_; + auto current_idx = tip_idx; + int32_t current_height = index.get_height(tip_idx); - while (height > 0) { - if (height <= step) { - height = 0; - } else { - height -= step; - } + while (current_height > 0 && locator.size() < 64) { + int32_t target_height = current_height > static_cast(step) + ? current_height - static_cast(step) + : 0; - auto const hash = chain_.get_block_hash(height); - if (hash) { - locator.push_back(*hash); + // Use O(log n) ancestor lookup via skip pointers + auto ancestor_idx = index.get_ancestor(current_idx, target_height); + if (ancestor_idx == blockchain::header_index::null_index) { + break; } + locator.push_back(index.get_hash(ancestor_idx)); + current_idx = ancestor_idx; + current_height = target_height; + if (locator.size() >= 10) { step *= 2; } - - if (locator.size() >= 64) { - break; - } } - // Always include genesis - if (height > 0) { - auto const genesis_hash = chain_.get_block_hash(0); - if (genesis_hash) { - locator.push_back(*genesis_hash); + // Always include genesis if not already included + if (current_height > 0) { + auto genesis_idx = index.get_ancestor(current_idx, 0); + if (genesis_idx != blockchain::header_index::null_index) { + locator.push_back(index.get_hash(genesis_idx)); } } @@ -440,13 +585,82 @@ bool sync_session::is_synced() const { } std::pair sync_session::current_heights() const { - return {organizer_.header_height(), block_height_}; + auto const h = organizer_.header_height(); + return {h >= 0 ? size_t(h) : 0, block_height_}; } // ============================================================================= // Utility Functions // ============================================================================= +/// Select the best peer for sync using BCHN logic: +/// 1. Prefer "preferred download" peers (fPreferredDownload in BCHN) +/// 2. If no preferred peers available, use any full node that's ahead of us +/// 3. Among candidates, prefer the one with highest reported height +/// +/// BCHN's logic (net_processing.cpp): +/// fPreferredDownload = (!fInbound || HasPermission(PF_NOBAN)) +/// && !fOneShot && !fClient; +/// fFetch = fPreferredDownload || (nPreferredDownload == 0 && !fClient && !fOneShot); +static peer_session::ptr select_sync_peer( + std::vector const& peers, + size_t our_height) +{ + peer_session::ptr best_preferred = nullptr; + peer_session::ptr best_fallback = nullptr; + uint32_t best_preferred_height = 0; + uint32_t best_fallback_height = 0; + + for (auto const& peer : peers) { + if (peer->stopped()) { + continue; + } + + auto version = peer->peer_version(); + if (!version) { + continue; + } + + auto const height = version->start_height(); + + // Only consider peers ahead of us + if (height <= our_height) { + continue; + } + + // BCHN: fPreferredDownload = (!fInbound || PF_NOBAN) && !fOneShot && !fClient + if (peer->is_preferred_download()) { + if (height > best_preferred_height) { + best_preferred = peer; + best_preferred_height = height; + } + } else if (!peer->is_one_shot() && !peer->is_client()) { + // BCHN fallback: nPreferredDownload == 0 && !fClient && !fOneShot + if (height > best_fallback_height) { + best_fallback = peer; + best_fallback_height = height; + } + } + } + + // Prefer "preferred download" peer if available + if (best_preferred) { + spdlog::debug("[sync] Selected preferred peer with height {} (outbound or whitelisted full node)", + best_preferred_height); + return best_preferred; + } + + // Fall back to any full node if no preferred peers available + // (BCHN: nPreferredDownload == 0 && !fClient && !fOneShot) + if (best_fallback) { + spdlog::debug("[sync] Selected fallback peer with height {} (no preferred peers available)", + best_fallback_height); + return best_fallback; + } + + return nullptr; +} + ::asio::awaitable sync_from_best_peer( block_chain& chain, p2p_node& p2p, @@ -455,12 +669,31 @@ ::asio::awaitable sync_from_best_peer( { sync_result result{}; - // Get current chain heights + // Get current chain heights - use header index for sync selection + // During headers-first sync, header index > persisted headers > blocks size_t our_block_height = 0; + size_t our_db_header_height = 0; auto const heights = chain.get_last_heights(); if (heights) { + our_db_header_height = heights->first; our_block_height = heights->second; } + // Header index may have more headers than persisted to DB + size_t our_header_height = chain.headers().size(); + if (our_header_height > 0) { + --our_header_height; // size() is count, height is count-1 + } + + // For peer selection: + // - If we need blocks (block_height < header_height), use block_height + // so we select peers that can give us blocks + // - If headers and blocks are synced, use header_height for new blocks + size_t our_sync_height = (our_block_height < our_header_height) + ? our_block_height // Need blocks - select peers ahead of our block height + : std::max({our_header_height, our_db_header_height, our_block_height}); + + // BCHN-style: don't wait for minimum peers, start sync immediately + // when any suitable peer is available // Get all connected peers auto peers = co_await p2p.peers().all(); @@ -471,43 +704,246 @@ ::asio::awaitable sync_from_best_peer( co_return result; } - spdlog::info("[sync] Selecting sync peer from {} connected peers, our height: {}", - peers.size(), our_block_height); + // Peers below max checkpoint are useless for sync + auto const max_checkpoint_height = chain.chain_settings().max_checkpoint_height; - // Find peer with highest start_height that's ahead of us - peer_session::ptr best_peer; - uint32_t best_height = 0; + // Filter out peers below max checkpoint + auto const initial_peer_count = peers.size(); + peers.erase( + std::remove_if(peers.begin(), peers.end(), + [max_checkpoint_height](auto const& peer) { + auto version = peer->peer_version(); + return !version || size_t(version->start_height()) < max_checkpoint_height; + }), + peers.end()); - for (auto const& peer : peers) { - auto version = peer->peer_version(); - if (!version) { - continue; - } + if (peers.empty()) { + spdlog::warn("[sync] No peers at or above checkpoint height {} (filtered {} peers)", + max_checkpoint_height, initial_peer_count); + result.error = error::channel_stopped; + co_return result; + } - auto const peer_height = version->start_height(); + if (peers.size() < initial_peer_count) { + spdlog::debug("[sync] Filtered {} peers below checkpoint height {}", + initial_peer_count - peers.size(), max_checkpoint_height); + } - if (peer_height <= our_block_height) { - continue; + // Count peers by type for logging + size_t preferred_count = 0; + size_t full_node_count = 0; + for (auto const& peer : peers) { + if (peer->is_preferred_download()) { + ++preferred_count; + } + if (peer->is_full_node()) { + ++full_node_count; } + } - if (peer_height > best_height) { - best_height = peer_height; - best_peer = peer; + // Calculate max height across all peers (BCHN-style) + // Don't trust just one peer's reported height + size_t max_peer_height = 0; + for (auto const& peer : peers) { + auto version = peer->peer_version(); + if (version) { + max_peer_height = std::max(max_peer_height, size_t(version->start_height())); } } + spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), " + "our height: {} (headers: {}, blocks: {}), checkpoint: {}, max peer: {}", + peers.size(), preferred_count, full_node_count, + our_sync_height, our_header_height, our_block_height, max_checkpoint_height, max_peer_height); + + // Select best peer using BCHN logic + auto best_peer = select_sync_peer(peers, our_sync_height); + if (!best_peer) { - spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_block_height); + // Check if there are peers with higher height that we couldn't sync from + // (e.g., all were banned or filtered out) + if (max_peer_height > our_sync_height) { + spdlog::info("[sync] No suitable peers found among {} remaining (none ahead of height {})", + peers.size(), our_sync_height); + result.error = error::operation_failed; + result.final_height = our_sync_height; + co_return result; + } + // Truly synced - no peers have higher height + spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_sync_height); result.error = error::success; - result.final_height = our_block_height; + result.final_height = our_sync_height; co_return result; } - spdlog::info("[sync] Selected peer [{}] with height {} for sync", - best_peer->authority(), best_height); + auto version = best_peer->peer_version(); + auto const best_height = version ? version->start_height() : 0; + + spdlog::info("[sync] Selected {} peer [{}] with height {} for sync (target: {})", + best_peer->is_preferred_download() ? "preferred" : "fallback", + best_peer->authority_with_agent(), best_height, max_peer_height); + + // Run sync with selected peer, using max_peer_height as target + // Pass p2p_node to enable parallel block download + auto session = make_sync_session(chain, best_peer, network, config, max_peer_height, &p2p); + result = co_await session->run(); + + // BCHN-style: If sync failed (including timeout), try another peer + // Timeout means peer is too slow - disconnect and try another + if (result.error) { + if (result.timed_out) { + spdlog::warn("[sync] Peer [{}] timed out (too slow), disconnecting and trying another...", + best_peer->authority_with_agent()); + // BCHN disconnects slow peers + best_peer->stop(error::channel_timeout); + } else if (result.error == error::checkpoints_failed) { + // BCHN bans peers that send headers failing checkpoint validation + // This typically indicates a peer on a different chain (BSV, etc.) + spdlog::warn("[sync] Peer [{}] sent headers failing checkpoint (wrong chain?), banning permanently...", + best_peer->authority_with_agent()); + p2p.ban_peer(best_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + } else if (result.error == error::store_block_missing_parent) { + // Headers don't connect to our chain - peer is likely on a different chain + spdlog::warn("[sync] Peer [{}] sent headers that don't connect (wrong chain?), banning permanently...", + best_peer->authority_with_agent()); + p2p.ban_peer(best_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + } else { + spdlog::warn("[sync] Sync with [{}] failed: {}, trying another peer...", + best_peer->authority_with_agent(), result.error.message()); + } + + // Remove failed peer from consideration and try again + peers.erase( + std::remove(peers.begin(), peers.end(), best_peer), + peers.end()); + + spdlog::debug("[sync] {} peers remaining after removing failed peer", peers.size()); + + // Retry with remaining peers until we succeed or run out of peers + int retry = 0; + while (!peers.empty()) { + auto retry_peer = select_sync_peer(peers, our_sync_height); + if (!retry_peer) { + spdlog::info("[sync] No suitable peers found among {} remaining (none ahead of height {})", + peers.size(), our_sync_height); + break; + } + + ++retry; + version = retry_peer->peer_version(); + auto const retry_height = version ? version->start_height() : 0; + spdlog::info("[sync] Retry {}: {} peer [{}] height {} (target: {})", + retry, + retry_peer->is_preferred_download() ? "preferred" : "fallback", + retry_peer->authority_with_agent(), retry_height, max_peer_height); + + auto retry_session = make_sync_session(chain, retry_peer, network, config, max_peer_height, &p2p); + result = co_await retry_session->run(); + + if (!result.error) { + break; // Success! + } + + if (result.timed_out) { + spdlog::warn("[sync] Retry peer [{}] timed out, disconnecting...", + retry_peer->authority_with_agent()); + retry_peer->stop(error::channel_timeout); + } else if (result.error == error::checkpoints_failed) { + // Ban peers that fail checkpoint (wrong chain) + spdlog::warn("[sync] Retry peer [{}] sent headers failing checkpoint (wrong chain?), banning permanently...", + retry_peer->authority_with_agent()); + p2p.ban_peer(retry_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + } else if (result.error == error::store_block_missing_parent) { + // Headers don't connect - wrong chain + spdlog::warn("[sync] Retry peer [{}] sent headers that don't connect (wrong chain?), banning permanently...", + retry_peer->authority_with_agent()); + p2p.ban_peer(retry_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + } + + // Remove this peer and try next + peers.erase( + std::remove(peers.begin(), peers.end(), retry_peer), + peers.end()); + } + } + + co_return result; +} + +// ============================================================================= +// Header Persistence (Background Task) +// ============================================================================= + +// Free function for header persistence - captures only what it needs +// so it can safely run after sync_session is destroyed +static ::asio::awaitable persist_headers_background( + block_chain& chain, + header_index const& index, + size_t start_height, + size_t end_height) +{ + if (start_height > end_height) { + spdlog::debug("[sync] No headers to persist (start {} > end {})", start_height, end_height); + co_return; + } + + auto const total_to_persist = end_height - start_height + 1; + spdlog::info("[sync] Starting background header persistence: {} headers ({} to {})", + total_to_persist, start_height, end_height); + + auto const persist_start = std::chrono::steady_clock::now(); + + // Persist in batches to avoid holding large vectors in memory + constexpr size_t batch_size = 1000; + + size_t persisted = 0; + size_t height = start_height; + + while (height <= end_height) { + // Build batch of headers + domain::chain::header::list batch; + auto const batch_end = std::min(height + batch_size - 1, end_height); + batch.reserve(batch_end - height + 1); + + for (size_t h = height; h <= batch_end; ++h) { + // During IBD, index == height (headers added in order) + batch.push_back(index.get_header(static_cast(h))); + } + + // Persist batch to database + auto const ec = chain.organize_headers_batch(batch, height); + if (ec) { + spdlog::warn("[sync] Header persistence failed at height {}: {}", + height, ec.message()); + // Don't abort - headers are still in memory for block sync + co_return; + } + + persisted += batch.size(); + height = batch_end + 1; + + // Log progress every 50000 headers + if (persisted % 50000 < batch_size) { + auto const elapsed = std::chrono::steady_clock::now() - persist_start; + auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); + auto const rate = elapsed_secs > 0 ? persisted / elapsed_secs : persisted; + spdlog::info("[sync] Header persistence progress: {}/{} ({}/s)", + persisted, total_to_persist, rate); + } + + // Yield to allow other coroutines to run + co_await ::asio::post(co_await ::asio::this_coro::executor, ::asio::use_awaitable); + } + + auto const elapsed = std::chrono::steady_clock::now() - persist_start; + auto const elapsed_ms = std::chrono::duration_cast(elapsed).count(); + spdlog::info("[sync] Header persistence complete: {} headers in {}ms", + persisted, elapsed_ms); +} - auto session = make_sync_session(chain, best_peer, network, config); - co_return co_await session->run(); +// Member function wrapper (for declaration compatibility) +::asio::awaitable sync_session::persist_headers_to_db(size_t start_height, size_t end_height) { + co_await persist_headers_background(chain_, organizer_.index(), start_height, end_height); } } // namespace kth::node From e695df2e725154270823f85b647e4413f8779702 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Fri, 19 Dec 2025 16:27:48 +0100 Subject: [PATCH 09/14] docs: add placeholder for structured logging system (#158) See issue #157 for full implementation details. --- .../infrastructure/log/structured_logger.hpp | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/infrastructure/include/kth/infrastructure/log/structured_logger.hpp diff --git a/src/infrastructure/include/kth/infrastructure/log/structured_logger.hpp b/src/infrastructure/include/kth/infrastructure/log/structured_logger.hpp new file mode 100644 index 00000000..4bc35103 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/log/structured_logger.hpp @@ -0,0 +1,83 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_LOG_STRUCTURED_LOGGER_HPP +#define KTH_INFRASTRUCTURE_LOG_STRUCTURED_LOGGER_HPP + +// ============================================================================= +// TODO: Implement Modern Structured Logging System +// ============================================================================= +// +// This file will contain the new structured logging infrastructure for Knuth. +// +// ## Goals: +// +// 1. **Dual Output**: +// - Console (human): Single-line progress updates using \r (like wget/docker) +// - File (machine): JSON structured logs for processing by ELK/Grafana/etc. +// +// 2. **Structured Events** (not messages): +// ```cpp +// log::event("sync_progress", { +// {"phase", 1}, +// {"current", 910000}, +// {"target", 930078}, +// {"rate", 32500}, +// {"eta_secs", 0} +// }); +// ``` +// +// 3. **Console Output** (human-friendly): +// - Progress bar with single-line updates: +// `Syncing headers: 910,000/930,078 (97%) [=========> ] 32,500/s ETA 0s` +// - Only show important events (errors, phase transitions) +// - No scrolling wall of text +// +// 4. **File Output** (machine-friendly JSON): +// ```json +// {"ts":"2025-12-19T13:47:10.177Z","level":"info","event":"sync_progress","phase":1,"current":910000,"target":930078,"rate":32500,"eta_secs":0} +// ``` +// +// 5. **Automatic Context**: +// - Timestamp (ISO 8601) +// - Log level +// - Thread/coroutine ID (optional) +// - Correlation ID for request tracing (optional) +// +// 6. **Log Levels**: +// - TRACE: Deep debugging +// - DEBUG: Development details +// - INFO: Business events (operator-visible) +// - WARN: Recoverable issues +// - ERROR: Failures needing attention +// - FATAL: Cannot continue +// +// 7. **Sampling** for high-volume events: +// ```cpp +// log::sampled(1000).debug("header_processed", {{"height", h}}); +// ``` +// +// ## Implementation Notes: +// +// - Console output: Direct stdout writes with ANSI escape codes, NOT through spdlog +// - File output: spdlog with custom JSON formatter +// - Consider using a progress bar library (e.g., indicators) for console +// - Keep existing spdlog infrastructure for file logging +// - New API should coexist with current logging during migration +// +// ## References: +// +// - spdlog custom formatters: https://github.com/gabime/spdlog/wiki/3.-Custom-formatting +// - indicators library: https://github.com/p-ranav/indicators +// - Structured logging patterns: https://www.honeycomb.io/blog/structured-logging-and-your-team +// +// ============================================================================= + +namespace kth::log { + +// TODO: Implement structured logging classes here + +} // namespace kth::log + +#endif // KTH_INFRASTRUCTURE_LOG_STRUCTURED_LOGGER_HPP From 80684ae60f829bded5b53fe1c57fcad61d98a7be Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Mon, 5 Jan 2026 00:58:07 +0100 Subject: [PATCH 10/14] feat(node): structured concurrency with task_group and parallel block download (#162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(executor): modernize executor with internal io_context and graceful shutdown - Refactor executor to own its io_context and run it in a dedicated thread - Replace three atomic bools with single state enum (stopped/starting/running/stopping) - Move user_agent configuration from executor to full_node - Add stopped() checks to all peer_manager async methods to prevent strand access after pool shutdown (fixes segfault on Ctrl-C) - Fix signal handling in wait_for_stop_signal() with proper work_guard - Update C API to use new executor interface - Improve TUI dashboard with network statistics display - Inline KTH_* message macros directly where used * feat(network): implement structured concurrency with task_group and peer_supervisor Replace detached coroutines with structured concurrency patterns: - Add task_group utility for managing parallel coroutines with automatic cleanup - Implement peer_supervisor as a nursery that manages peer lifecycles - Use concurrent_channel for peer events instead of fire-and-forget spawns - Add supervisor_ready_ atomic for deterministic synchronization - Close response channels (headers_responses_, block_responses_) on peer stop to properly propagate shutdown to waiting sync operations - Modernize executor with internal io_context and graceful shutdown - Fix thread_ceiling to use all cores when threads=0 Key changes: - p2p_node::run() now uses task_group instead of co_spawn with detached - peer_supervisor tracks all peer tasks and waits for completion on shutdown - Clean shutdown: all coroutines complete orderly, "Good bye!" prints reliably - Manual peer connections wait for supervisor_ready_ before connecting * feat(node): add parallel block download with lock-free coordinator v2 Implement parallel block download system with two coordinator versions: V1 (strand-based): - Uses asio::strand for serialization instead of mutex - Avoids coroutine blocking issues from std::mutex V2 (lock-free): - Atomic CAS operations for chunk claiming - Slot-based system: 800 slots per round (8 peers × 100 multiplier) - 3 states: FREE (0), IN_PROGRESS (1), COMPLETED (2) - Peer watcher detects and adds new peers dynamically - Round advances when all slots complete Features: - Parallel downloads from multiple peers simultaneously - In-order block validation pipeline - Timeout detection for stalled downloads - Dynamic peer addition during sync - Progress logging with ETA, peer count, in-flight chunks Files added: - block_download_coordinator.hpp/cpp (V1) - block_download_coordinator_v2.hpp/cpp (V2) - parallel_sync.hpp/cpp (V1) - parallel_sync_v2.hpp/cpp (V2) # Conflicts: # src/blockchain/include/kth/blockchain/pools/header_organizer.hpp # src/blockchain/src/pools/header_organizer.cpp # src/network/include/kth/network/peer_session.hpp # src/network/src/banlist.cpp # src/network/src/p2p_node.cpp # src/network/src/peer_manager.cpp # src/network/src/peer_session.cpp # src/node-exe/src/main.cpp # src/node/include/kth/node.hpp # src/node/include/kth/node/sync_session.hpp # src/node/src/executor/executor.cpp # src/node/src/full_node.cpp --- banlist.dat | 1 + docs/design/STRUCTURED_CONCURRENCY_DESIGN.md | 383 ++++++++++ docs/parallel-block-download.md | 567 ++++++++++++++ hosts.cache | 645 ++++++++++++++++ .../kth/blockchain/interface/block_chain.hpp | 4 +- .../kth/blockchain/pools/block_organizer.hpp | 3 +- .../kth/blockchain/pools/header_organizer.hpp | 158 ++-- .../include/kth/blockchain/settings.hpp | 2 + .../blockchain/validate/validate_block.hpp | 21 +- .../blockchain/validate/validate_header.hpp | 83 +++ src/blockchain/src/pools/block_organizer.cpp | 8 +- src/blockchain/src/pools/header_organizer.cpp | 308 +++----- .../src/populate/populate_chain_state.cpp | 2 +- src/blockchain/src/settings.cpp | 6 + .../src/validate/validate_block.cpp | 128 +++- .../src/validate/validate_header.cpp | 316 +++++++- src/c-api/src/node.cpp | 49 +- src/consensus/src/bch-rules/coins.h | 2 +- .../src/bch-rules/script/interpreter.cpp | 2 +- .../src/bch-rules/util/strencodings.h | 2 +- .../src/btc-rules/script/interpreter.cpp | 2 +- .../database/databases/internal_database.ipp | 13 +- src/domain/include/kth/domain/chain/block.hpp | 7 +- .../include/kth/domain/chain/block_basis.hpp | 16 +- .../include/kth/domain/chain/header.hpp | 2 - .../include/kth/domain/chain/header_basis.hpp | 4 - .../include/kth/domain/config/parser.hpp | 7 +- .../include/kth/domain/constants/common.hpp | 9 +- src/domain/src/chain/block.cpp | 18 +- src/domain/src/chain/block_basis.cpp | 140 +--- src/domain/src/chain/header.cpp | 4 - src/domain/src/chain/header_basis.cpp | 25 - .../include/kth/infrastructure.hpp | 2 + .../infrastructure/utility/cpu_executor.hpp | 157 ++++ .../kth/infrastructure/utility/task_group.hpp | 230 ++++++ src/infrastructure/src/log/sink.cpp | 17 +- .../src/utility/system_memory.cpp | 18 +- src/network/include/kth/network/p2p_node.hpp | 36 + .../include/kth/network/peer_session.hpp | 141 +++- .../include/kth/network/protocols_coro.hpp | 37 + src/network/include/kth/network/settings.hpp | 1 + src/network/src/banlist.cpp | 236 ++++++ src/network/src/handlers/pong.cpp | 10 +- src/network/src/p2p_node.cpp | 691 +++++++++++++----- src/network/src/peer_manager.cpp | 50 +- src/network/src/peer_session.cpp | 320 +++++++- src/network/src/protocols_coro.cpp | 230 ++++++ src/network/src/settings.cpp | 6 +- src/node-exe/src/main.cpp | 113 ++- src/node-exe/src/tui_dashboard.cpp | 244 ++++++- src/node-exe/src/tui_dashboard.hpp | 22 + src/node/CMakeLists.txt | 8 + src/node/data/bn.cfg | 4 +- src/node/include/kth/node.hpp | 3 +- .../kth/node/block_download_coordinator.hpp | 235 ++++++ .../node/block_download_coordinator_v2.hpp | 238 ++++++ .../include/kth/node/executor/executor.hpp | 172 +++-- src/node/include/kth/node/full_node.hpp | 7 + src/node/include/kth/node/parallel_sync.hpp | 44 ++ .../include/kth/node/parallel_sync_v2.hpp | 39 + src/node/include/kth/node/sync_session.hpp | 61 +- src/node/src/block_download_coordinator.cpp | 360 +++++++++ .../src/block_download_coordinator_v2.cpp | 411 +++++++++++ src/node/src/executor/executor.cpp | 566 ++++++++------ src/node/src/full_node.cpp | 216 ++++-- src/node/src/parallel_sync.cpp | 376 ++++++++++ src/node/src/parallel_sync_v2.cpp | 382 ++++++++++ src/node/src/parser.cpp | 4 +- tui_screenshot.png | Bin 0 -> 1232582 bytes 69 files changed, 7387 insertions(+), 1237 deletions(-) create mode 100644 banlist.dat create mode 100644 docs/design/STRUCTURED_CONCURRENCY_DESIGN.md create mode 100644 docs/parallel-block-download.md create mode 100644 hosts.cache create mode 100644 src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp create mode 100644 src/infrastructure/include/kth/infrastructure/utility/task_group.hpp create mode 100644 src/network/src/banlist.cpp create mode 100644 src/node/include/kth/node/block_download_coordinator.hpp create mode 100644 src/node/include/kth/node/block_download_coordinator_v2.hpp create mode 100644 src/node/include/kth/node/parallel_sync.hpp create mode 100644 src/node/include/kth/node/parallel_sync_v2.hpp create mode 100644 src/node/src/block_download_coordinator.cpp create mode 100644 src/node/src/block_download_coordinator_v2.cpp create mode 100644 src/node/src/parallel_sync.cpp create mode 100644 src/node/src/parallel_sync_v2.cpp create mode 100644 tui_screenshot.png diff --git a/banlist.dat b/banlist.dat new file mode 100644 index 00000000..0e5abcaf --- /dev/null +++ b/banlist.dat @@ -0,0 +1 @@ +# Knuth banlist - format: IP create_time ban_until reason diff --git a/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md b/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md new file mode 100644 index 00000000..55effc3e --- /dev/null +++ b/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md @@ -0,0 +1,383 @@ +# Structured Concurrency Design for Knuth Network Layer + +> **IMPORTANT**: This document is the source of truth for the network layer refactoring. +> Always read this document at the start of each session to understand the design goals. +> Location: `docs/design/STRUCTURED_CONCURRENCY_DESIGN.md` + +## Overview + +This document describes the refactoring of the Knuth network layer from "fire-and-forget" +coroutines (`::asio::detached`) to a structured concurrency model inspired by Go channels +and Kotlin coroutines. + +## Design Principles + +1. **No `::asio::detached`** except at the top-level entry point +2. **All coroutines must be awaited** - parent waits for all children +3. **Channel-based coordination** - Go-style message passing +4. **Separate IO and CPU executors** - maximize parallelism +5. **Graceful shutdown by design** - no race conditions + +## Current Problems + +```cpp +// PROBLEM: Fire-and-forget coroutines +::asio::co_spawn(executor, peer->run(), ::asio::detached); // Lost track! +::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); // Lost track! + +// PROBLEM: Race condition on shutdown +if (stopped()) { co_return; } // Check here... +co_await some_async_op(); // ...but stop() called here = crash +``` + +## Target Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ executor::run_async() │ +│ (single detached entry point) │ +│ ┌───────────────────────────────────────────────────────────────────┐ │ +│ │ full_node::run() │ │ +│ │ co_await ( │ │ +│ │ run_blockchain_subscriber() && │ │ +│ │ network_.run() && │ │ +│ │ run_sync() │ │ +│ │ ); │ │ +│ │ │ │ │ +│ │ ▼ │ │ +│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ +│ │ │ p2p_node::run() │ │ │ +│ │ │ co_await ( │ │ │ +│ │ │ run_inbound() && │ │ │ +│ │ │ run_outbound() && │ │ │ +│ │ │ peer_supervisor() ← manages all peer lifecycles │ │ │ +│ │ │ ); │ │ │ +│ │ └─────────────────────────────────────────────────────────────┘ │ │ +│ └───────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +## Key Components + +### 1. task_group (Nursery Pattern) + +New class to manage dynamic tasks without detached: + +```cpp +// File: src/infrastructure/include/kth/infrastructure/utility/task_group.hpp + +class task_group { +public: + explicit task_group(::asio::any_io_executor executor); + + // Spawn a task - tracked automatically + template + void spawn(Coro&& coro); + + // Spawn and get a handle to cancel later + template + task_handle spawn_with_handle(Coro&& coro); + + // Wait for ALL tasks to complete + ::asio::awaitable join(); + + // Cancel all tasks and wait + ::asio::awaitable cancel_and_join(); + + // Number of active tasks + size_t active_count() const; + +private: + ::asio::any_io_executor executor_; + std::atomic active_count_{0}; + ::asio::experimental::channel done_signal_; +}; +``` + +### 2. peer_supervisor + +Centralized peer lifecycle management: + +```cpp +// In p2p_node + +::asio::awaitable peer_supervisor() { + task_group peer_tasks(pool_.get_executor()); + + while (!stopped_) { + // Wait for new peer OR shutdown + auto event = co_await ( + new_peer_channel_.async_receive(::asio::use_awaitable) || + stop_signal_.async_receive(::asio::use_awaitable) + ); + + if (event.index() == 1) break; // shutdown + + auto [peer, direction] = std::get<0>(event); + + peer_tasks.spawn([this, peer]() -> ::asio::awaitable { + co_await peer->run_full(dispatcher_); + co_await manager_.remove(peer); + spdlog::debug("[p2p_node] Peer {} task completed", peer->authority()); + }); + } + + // CRITICAL: Wait for all peer tasks to finish + co_await peer_tasks.join(); +} +``` + +### 3. Unified peer_session::run_full() + +Single coroutine for entire peer lifecycle: + +```cpp +// In peer_session + +::asio::awaitable run_full(message_dispatcher& dispatcher) { + // All loops run in parallel, all must complete + co_await ( + read_loop() && + write_loop() && + run_protocols(dispatcher) && + inactivity_monitor() && + expiration_monitor() + ); +} +``` + +### 4. Channel-based Coordination + +```cpp +// New channels in p2p_node +struct { + // New peers to be supervised + concurrent_channel new_peer_channel_; + + // Shutdown signal + concurrent_channel stop_signal_; + +} channels_; + +// peer_event structure +struct peer_event { + peer_session::ptr peer; + enum class direction { inbound, outbound } dir; +}; +``` + +### 5. Separate CPU Executor + +```cpp +// For CPU-bound work (validation, etc.) +class cpu_executor { +public: + explicit cpu_executor(size_t threads = std::thread::hardware_concurrency()); + + template + auto post(F&& work) -> ::asio::awaitable>; + + void stop(); + void join(); + +private: + ::asio::thread_pool pool_; +}; +``` + +## Implementation Phases + +### Phase 1: Infrastructure ✅ COMPLETE +- [x] Make `run_inbound()` and `run_outbound()` awaited in `p2p_node::run()` +- [x] Make `full_node::run()` use `&&` operator for parallel tasks +- [x] Create `task_group` class (`src/infrastructure/.../utility/task_group.hpp`) +- [x] Create `cpu_executor` class (`src/infrastructure/.../utility/cpu_executor.hpp`) + +### Phase 2: Peer Lifecycle Refactoring ✅ COMPLETE +- [x] Add `new_peer_channel_` and `stop_signal_` to p2p_node +- [x] Implement `peer_supervisor()` with task_group +- [x] Modify `connect()` to send peer_event to channel with response channel +- [x] Modify `run_inbound()` to send peer_event to channel +- [x] Eliminate `peer->run()` detached spawns using `&&` operator pattern + - supervisor does: `peer->run() && (handshake && add && protocols)` + - connect() waits for handshake result via response channel + +### Phase 3: Connection Management ✅ COMPLETE +- [x] Refactor `run_inbound()` to send new peers to channel (done in Phase 2) +- [x] Refactor `maintain_outbound_connections()` to use task_group for parallel connects +- [x] Refactor seeding to use task_group + +### Phase 4: Cleanup ✅ COMPLETE +- [x] Fix `stop_all()` to NOT clear peers_ map (let remove() handle cleanup) +- [x] Remove `stopped()` check from `remove()` and `remove_by_nonce()` +- [x] Remove all `::asio::detached` from p2p_node.cpp (using `&&` operator pattern) +- [ ] Remove remaining `stopped()` checks from query methods (optional - they're defensive) +- [ ] Update tests + +### Phase 5: CPU Parallelism +- [ ] Integrate `cpu_executor` for block validation +- [ ] Add parallel header validation +- [ ] Add parallel transaction validation + +## Files to Modify + +| File | Changes | +|------|---------| +| `src/infrastructure/.../utility/task_group.hpp` | **DONE** - task_group class | +| `src/infrastructure/.../utility/cpu_executor.hpp` | **DONE** - CPU executor | +| `src/network/include/kth/network/p2p_node.hpp` | Add channels, peer_supervisor | +| `src/network/src/p2p_node.cpp` | Refactor connect/inbound/outbound | +| `src/network/include/kth/network/peer_session.hpp` | Add run_full() | +| `src/network/src/peer_session.cpp` | Implement run_full() | +| `src/network/src/peer_manager.cpp` | Remove stopped() checks | +| `src/node/src/full_node.cpp` | Already done - uses && | + +## Message Flow (Go-style) + +``` + ┌─────────────────┐ + │ run_inbound() │ + │ (accept loop) │ + └────────┬────────┘ + │ new peer + ▼ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ run_outbound() │───▶│ new_peer_channel│◀───│ connect() │ +│ (connect loop) │ └────────┬────────┘ │ (manual peer) │ +└─────────────────┘ │ └─────────────────┘ + ▼ + ┌─────────────────────┐ + │ peer_supervisor() │ + │ │ + │ task_group { │ + │ peer1.run_full() │ + │ peer2.run_full() │ + │ peer3.run_full() │ + │ ... │ + │ } │ + └─────────────────────┘ + │ + ▼ on stop() + ┌─────────────────────┐ + │ task_group.join() │ + │ (wait for all) │ + └─────────────────────┘ +``` + +## Shutdown Sequence + +``` +1. stop() called + │ + ├─▶ stop_signal_.send() // Signal supervisor to stop accepting + ├─▶ acceptor_.close() // Stop accepting new connections + └─▶ manager_.stop_all() // Signal all peers to stop + +2. peer_supervisor() receives stop_signal_ + │ + └─▶ Exits while loop, calls peer_tasks.join() + │ + └─▶ Waits for ALL peer->run_full() to complete + │ + └─▶ Each peer: socket closes → loops exit → run_full() returns + +3. run_inbound() exits (acceptor closed) + +4. run_outbound() exits (stopped_ = true) + +5. p2p_node::run() returns (all && branches completed) + +6. full_node::run() returns + +7. executor cleans up io_context + +NO RACE CONDITIONS - everything is awaited! +``` + +## Testing Strategy + +1. **Unit tests for task_group** + - spawn/join behavior + - cancel_and_join behavior + - exception propagation + +2. **Integration tests** + - Clean shutdown with active peers + - Shutdown during connection attempts + - Shutdown during handshake + +3. **Stress tests** + - Many concurrent connections + - Rapid connect/disconnect cycles + - Shutdown under load + +## References + +- [Trio Structured Concurrency](https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning) +- [Kotlin Structured Concurrency](https://kotlinlang.org/docs/coroutines-basics.html#structured-concurrency) +- [ASIO Awaitable Operators](https://think-async.com/Asio/asio-1.28.0/doc/asio/overview/composition/cpp20_coroutines.html) + +## Notes + +- The `&&` operator from `asio::experimental::awaitable_operators` runs coroutines + in parallel and waits for ALL to complete +- The `||` operator runs coroutines in parallel and completes when ANY finishes +- Channels use `asio::experimental::concurrent_channel` for thread-safety +- All peers share the same thread pool (`p2p_node::pool_`) + +## Remaining `::asio::detached` Uses + +These are the remaining detached uses in the codebase (excluding tests): + +### Legitimate / By Design + +| File | Location | Justification | +|------|----------|---------------| +| `task_group.hpp:97` | `spawn()` | Core mechanism - tasks are TRACKED via `active_count_` | +| `task_group.hpp:191` | `scoped_task_group` destructor | RAII blocking wait - expected behavior | +| `executor.cpp:232` | `stop_async()` | Top-level entry point from sync code (signal handlers) | + +### DEFERRED (Requires Restructuring) ✅ COMPLETE + +All `peer->run()` detached spawns have been eliminated using the `&&` operator pattern: + +| File | Location | Solution | +|------|----------|----------| +| `p2p_node.cpp` | `connect()` | Sends to supervisor, waits for handshake via response channel | +| `p2p_node.cpp` | `connect_to_seed()` | Uses `peer->run() && seeding_protocol()` directly | +| `p2p_node.cpp` | `run_inbound()` | Sends to supervisor (no wait needed for inbound) | +| `p2p_node.cpp` | `peer_supervisor()` | Uses `peer->run() && (handshake && add && protocols)` | + +**Pattern used**: The `&&` operator runs both coroutines in parallel. When peer disconnects, +both `run()` and the protocol branch exit, and `&&` completes. No detached needed! + +```cpp +// Structured concurrency pattern for peer lifecycle +peer_tasks.spawn([...]() -> awaitable { + co_await ( + peer->run() && // Message pump runs in parallel + [&]() -> awaitable { + co_await perform_handshake(*peer); // Uses channels (run() is running!) + co_await run_protocols(peer); + }() + ); // Both complete when peer disconnects +}); +``` + +## Future Work + +### High Priority +- [x] ~~Eliminate `peer->run()` detached spawns~~ ✅ COMPLETE + +### Medium Priority +- [ ] Review C API (`src/c-api/`) for structured concurrency patterns +- [ ] Update tests to use structured concurrency where applicable + +### Low Priority +- [ ] Consider making `executor::stop_async()` awaitable +- [ ] Add exception propagation to `task_group` + +--- + +**Last Updated**: 2025-12-22 +**Branch**: `feat/structured-concurrency` diff --git a/docs/parallel-block-download.md b/docs/parallel-block-download.md new file mode 100644 index 00000000..8dfb5a4d --- /dev/null +++ b/docs/parallel-block-download.md @@ -0,0 +1,567 @@ +# Parallel Block Download - Design Document + +## Problem Statement + +Current block download is sequential: request block N, wait for response, request block N+1. +With ~100ms round-trip latency, this limits throughput to ~10 blocks/second regardless of bandwidth. + +**Goal**: Download blocks in parallel from multiple peers to maximize throughput. + +## BCHN Reference Implementation + +BCHN uses a **centralized coordinator** with these parameters: + +```cpp +MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16 // per-peer pipeline depth +BLOCK_DOWNLOAD_WINDOW = 1024 // global look-ahead window +``` + +Key data structures: +- `mapBlocksInFlight`: global multimap (hash → peer_id) tracking ALL in-flight blocks +- `vBlocksInFlight`: per-peer list of blocks being downloaded + +Coordination logic: +1. For each peer, periodically check if `vBlocksInFlight.size() < 16` +2. Call `FindNextBlocksToDownload()` which skips blocks already in `mapBlocksInFlight` +3. Send single `getdata` with multiple block inventories +4. On block received: remove from tracking, process, loop automatically refills + +## Our Design: Block Download Coordinator + +### Architecture + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ BlockDownloadCoordinator │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ Shared State │ │ +│ │ - next_height_to_assign: atomic │ │ +│ │ - blocks_in_flight: map │ │ +│ │ - pending_blocks: map (out-of-order buffer) │ │ +│ │ - next_height_to_validate: uint32_t │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Peer 1 │ │ Peer 2 │ │ Peer 3 │ │ Peer N │ │ +│ │ in_flight: │ │ in_flight: │ │ in_flight: │ │ in_flight: │ │ +│ │ [h1,h2,h3] │ │ [h4,h5,h6] │ │ [h7,h8,h9] │ │ [...] │ │ +│ │ max: 16 │ │ max: 16 │ │ max: 16 │ │ max: 16 │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ Validation Pipeline │ │ +│ │ Processes blocks in order as they become available │ │ +│ │ next_height_to_validate → chain_.organize() │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Configuration + +```cpp +struct download_config { + size_t max_blocks_per_peer = 16; // pipeline depth per peer + size_t global_window = 1024; // max look-ahead + size_t target_peers = 8; // desired concurrent peers + std::chrono::seconds block_timeout = 60s; + std::chrono::seconds stall_timeout = 10s; +}; +``` + +### Core Components + +#### 1. BlockDownloadCoordinator + +Central coordinator that manages block assignments across peers. + +```cpp +class BlockDownloadCoordinator { +public: + // Called by sync_session to get next blocks to download + std::vector claim_blocks( + peer_session& peer, + size_t max_count // typically 16 + ); + + // Called when a block is received + void block_received( + hash_digest const& hash, + uint32_t height, + domain::message::block block + ); + + // Called when peer disconnects - reassign its blocks + void peer_disconnected(peer_session const& peer); + + // Called periodically to check for stalled downloads + void check_timeouts(); + + // Get next validated block for chain (blocks until available or timeout) + awaitable> next_validated_block(); + +private: + std::mutex mutex_; + + // Assignment tracking + uint32_t start_height_; + uint32_t target_height_; + std::atomic next_height_to_assign_; + + // In-flight tracking: height -> {peer, request_time, hash} + struct Assignment { + peer_session::ptr peer; + std::chrono::steady_clock::time_point requested_at; + hash_digest hash; + }; + std::map in_flight_; + + // Out-of-order buffer: height -> block + std::map pending_blocks_; + + // Validation state + uint32_t next_height_to_validate_; + + // Channel for validation pipeline + concurrent_channel validated_blocks_; +}; +``` + +#### 2. Peer Download Coroutine + +Each peer runs a download coroutine that: +1. Claims blocks from coordinator +2. Sends batch `getdata` +3. Receives blocks and reports to coordinator +4. Repeats + +```cpp +::asio::awaitable peer_download_loop( + peer_session::ptr peer, + BlockDownloadCoordinator& coordinator +) { + while (!stopped_ && peer->connected()) { + // Claim up to 16 blocks + auto blocks = coordinator.claim_blocks(*peer, 16); + if (blocks.empty()) { + // No more blocks or window full + co_await async_sleep(100ms); + continue; + } + + // Send batch getdata + co_await send_getdata(peer, blocks); + + // Receive blocks (with timeout) + for (size_t i = 0; i < blocks.size(); ++i) { + auto result = co_await receive_block_with_timeout(peer, 30s); + if (!result) { + // Timeout or error - coordinator will reassign + break; + } + coordinator.block_received(result->hash, result->height, std::move(*result)); + } + } +} +``` + +#### 3. Validation Pipeline + +Separate coroutine that processes blocks in order: + +```cpp +::asio::awaitable validation_pipeline( + BlockDownloadCoordinator& coordinator, + blockchain::block_chain& chain +) { + while (!stopped_) { + auto block = co_await coordinator.next_validated_block(); + if (!block) break; + + auto ec = co_await chain.organize(*block); + if (ec) { + // Handle validation failure + spdlog::error("Block validation failed at height {}", block->height()); + } + } +} +``` + +### Coordination Strategies + +#### Option A: Centralized (BCHN-style) + +``` +Coordinator assigns blocks sequentially: + Peer 1 gets: [1, 2, 3, ..., 16] + Peer 2 gets: [17, 18, 19, ..., 32] + Peer 3 gets: [33, 34, 35, ..., 48] + +As blocks complete, refill to maintain 16 per peer. +``` + +**Pros**: Simple, predictable, good locality +**Cons**: Single point of coordination + +#### Option B: Work Stealing (Decentralized) + +``` +Each peer claims ranges atomically: + next_to_claim.fetch_add(16) → gets exclusive range + +If peer stalls, others can "steal" unclaimed work. +``` + +**Pros**: Less contention, self-balancing +**Cons**: More complex, potential for gaps + +#### Option C: Hybrid (Recommended) + +``` +1. Coordinator assigns contiguous ranges to peers +2. Each peer manages its own in-flight window +3. On timeout/disconnect, coordinator reassigns to fastest peer +4. Adaptive: assign more blocks to faster peers +``` + +### Handling Edge Cases + +#### 1. Peer Disconnection + +```cpp +void BlockDownloadCoordinator::peer_disconnected(peer_session const& peer) { + std::lock_guard lock(mutex_); + + // Find all blocks assigned to this peer + std::vector to_reassign; + for (auto& [height, assignment] : in_flight_) { + if (assignment.peer.get() == &peer) { + to_reassign.push_back(height); + } + } + + // Move back to unassigned pool + for (auto height : to_reassign) { + in_flight_.erase(height); + // Will be claimed by next peer that asks + } +} +``` + +#### 2. Stalled Downloads + +```cpp +void BlockDownloadCoordinator::check_timeouts() { + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(mutex_); + + for (auto it = in_flight_.begin(); it != in_flight_.end(); ) { + if (now - it->second.requested_at > stall_timeout_) { + spdlog::warn("Block {} stalled from peer {}", + it->first, it->second.peer->authority()); + + // Ban slow peer or just reassign? + // For now, just reassign + it = in_flight_.erase(it); + } else { + ++it; + } + } +} +``` + +#### 3. Out-of-Order Blocks + +```cpp +void BlockDownloadCoordinator::block_received( + hash_digest const& hash, + uint32_t height, + block_ptr block +) { + std::lock_guard lock(mutex_); + + // Remove from in-flight + in_flight_.erase(height); + + if (height == next_height_to_validate_) { + // Perfect - validate immediately + validated_blocks_.try_send({}, std::move(block)); + ++next_height_to_validate_; + + // Check if we can validate more from pending + while (auto it = pending_blocks_.find(next_height_to_validate_); + it != pending_blocks_.end()) { + validated_blocks_.try_send({}, std::move(it->second)); + pending_blocks_.erase(it); + ++next_height_to_validate_; + } + } else { + // Out of order - buffer it + pending_blocks_[height] = std::move(block); + } +} +``` + +### Multi-Peer Orchestration + +```cpp +::asio::awaitable parallel_block_sync( + blockchain::block_chain& chain, + p2p_node& network, + uint32_t start_height, + uint32_t target_height +) { + BlockDownloadCoordinator coordinator(start_height, target_height); + + // Get all connected peers + auto peers = co_await network.peers().all(); + if (peers.empty()) { + co_return sync_result{error::no_peers}; + } + + // Create task group for all download coroutines + task_group download_tasks(network.thread_pool().get_executor()); + + // Spawn download loop for each peer + for (auto& peer : peers) { + download_tasks.spawn([&peer, &coordinator]() -> awaitable { + co_await peer_download_loop(peer, coordinator); + }); + } + + // Spawn validation pipeline + download_tasks.spawn([&coordinator, &chain]() -> awaitable { + co_await validation_pipeline(coordinator, chain); + }); + + // Spawn timeout checker + download_tasks.spawn([&coordinator]() -> awaitable { + while (!coordinator.complete()) { + co_await async_sleep(1s); + coordinator.check_timeouts(); + } + }); + + // Wait for all to complete + co_await download_tasks.join(); + + co_return sync_result{error::success, target_height - start_height}; +} +``` + +### Performance Expectations + +| Peers | Blocks/peer | Total In-Flight | Theoretical Speedup | +|-------|-------------|-----------------|---------------------| +| 1 | 16 | 16 | 16x | +| 4 | 16 | 64 | 64x | +| 8 | 16 | 128 | 128x | + +With 100ms latency and 16 blocks in-flight per peer: +- Single peer: 16 blocks / 100ms = 160 blocks/sec +- 8 peers: 128 blocks / 100ms = 1280 blocks/sec + +Actual throughput limited by: +- Bandwidth (block size × blocks/sec) +- Validation speed (CPU-bound) +- Disk I/O + +### Implementation Plan + +1. **Phase 1: BlockDownloadCoordinator class** + - Block assignment logic + - In-flight tracking + - Out-of-order buffering + +2. **Phase 2: Peer download coroutines** + - Batch getdata sending + - Block receiving with timeout + - Integration with coordinator + +3. **Phase 3: Validation pipeline** + - Ordered block processing + - Chain integration + +4. **Phase 4: Adaptive optimizations** + - Peer speed tracking + - Dynamic block assignment + - Slow peer detection + +### File Structure + +``` +src/node/ +├── block_download_coordinator.hpp +├── block_download_coordinator.cpp +├── parallel_sync.hpp +├── parallel_sync.cpp +└── sync_session.cpp (modified to use coordinator) +``` + +### Open Questions + +1. **Should we download from peers we're not fully connected to?** + - BCHN requires handshake complete before requesting blocks + +2. **How to handle forks/reorgs during download?** + - Need to validate headers first, then download blocks for winning chain + +3. **Memory limits for out-of-order buffer?** + - With 1024 window and avg 1MB blocks, could need 1GB buffer + - Consider disk-based buffering for large syncs + +4. **Prioritize recent blocks?** + - During IBD, oldest blocks first + - After IBD, newest blocks (for tip) should have priority + +--- + +## Implementation Status + +### Completed +- [x] `block_download_coordinator` class with parallel download management +- [x] `parallel_sync` orchestration with task_group (nursery pattern) +- [x] Integration with `sync_session` (automatic when p2p_node available) +- [x] Peer download loops with claim/receive pattern +- [x] Validation pipeline (in-order block validation) +- [x] Timeout checker for stalled downloads +- [x] Out-of-order buffering with flush to validation +- [x] Uses `boost::unordered_flat_map` for performance + +### Pending Optimizations + +1. **Batch getdata** (High Priority) + - Current: Each peer sends getdata one block at a time, waits for response + - Optimal: Send batch getdata (16 blocks), receive blocks via message handler + - Requires: New `receive_block_with_timeout()` function in `protocols_coro.hpp` + - Impact: Would reduce round-trip latency by ~16x per peer + +2. **Expose configuration in settings** (Medium Priority) + - Currently: `parallel_download_config` has hardcoded values + - TODO: Add to `node::settings` for user configuration + - Parameters: `max_blocks_per_peer`, `global_window`, `stall_timeout` + +3. **Dynamic memory limits** (Medium Priority) + - Issue: With window=1024 and ~1MB avg blocks, could use ~1GB in worst case + - TODO: Calculate `global_window` based on available system memory + - Consider: Disk-based buffering for very large syncs + +4. **Refactor coordinator to eliminate mutex** (Low Priority) + - Current: Uses `std::mutex` for thread-safe state access + - Alternatives to explore: + - Strand-based serialization (make `claim_blocks` awaitable) + - Actor model with command channel + - Note: Current mutex is acceptable due to low contention (~128 ops/sec) + +5. **Adaptive peer assignment** (Future Enhancement) + - Track peer download speeds + - Assign more blocks to faster peers + - Automatically deprioritize slow peers + +6. **Penalize slow peers** (Future Enhancement) + - If a peer consistently times out, reduce their block allocation + - Consider temporary banning for very slow peers + +--- + +## TODO: Parallel Validation Discussion + +### Current State: Sequential Validation + +Currently, validation happens sequentially: block N must be fully validated before block N+1. + +``` +Download: [====1====] [====2====] [====3====] [====4====] (parallel) +Validation: [====1====][====2====][====3====][====4====] (sequential) +``` + +### What CAN be parallelized? + +1. **Syntax/Format Validation** + - Block header format + - Transaction format + - Merkle root calculation + - Size limits + - These are independent per block + +2. **Script Validation (Signature Checks)** + - ECDSA/Schnorr signature verification is CPU-intensive + - Scripts within a block can be validated in parallel + - Scripts across blocks can potentially be validated in parallel (with caveats) + +3. **PoW Validation** + - Header hash < target + - Independent per block + +### What MUST be sequential? + +1. **UTXO Set Updates** + - Block N creates outputs that block N+1 might spend + - Must apply in order to maintain consistency + +2. **Contextual Validation** + - Coinbase maturity (100 blocks) + - Median time past + - Difficulty adjustment + - BIP activation heights + +### Proposed Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Download Phase │ +│ Peer1: [blk 100-115] Peer2: [blk 116-131] Peer3: [...] │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Pre-Validation (Parallel) │ +│ - Syntax checks │ +│ - Merkle root │ +│ - PoW validation │ +│ - Script validation (signatures) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Contextual Validation (Sequential) │ +│ - UTXO lookups and updates │ +│ - Coinbase maturity │ +│ - Median time past │ +│ - Connect to chain │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Questions to Discuss + +1. **Script validation across blocks**: + - Can we validate scripts for block N+1 while block N is being connected? + - Need to handle the case where N+1 spends an output created in N + +2. **Batch signature verification**: + - Schnorr signatures can be batch-verified (faster than individual) + - How to accumulate signatures across blocks? + +3. **UTXO cache strategy**: + - Pre-fetch UTXOs for upcoming blocks? + - Speculative execution with rollback? + +4. **Thread pool sizing**: + - How many threads for script validation? + - Separate pools for download vs validation? + +5. **Assumevalid optimization**: + - Skip script validation for blocks before a known-good hash + - Bitcoin Core uses this for faster IBD + +### References + +- BCHN parallel validation: `src/validation.cpp` +- Bitcoin Core `CheckInputScripts` parallelization +- libsecp256k1 batch verification + +--- + +## Discussion Notes + +(Add notes here as we discuss) diff --git a/hosts.cache b/hosts.cache new file mode 100644 index 00000000..a34d9f6e --- /dev/null +++ b/hosts.cache @@ -0,0 +1,645 @@ +23.191.200.9:19798 +65.21.79.59:8333 +101.69.226.138:8333 +35.193.139.211:8333 +94.25.187.239:8333 +75.164.137.188:8433 +83.221.211.116:8333 +143.105.117.74:8330 +70.57.97.122:8333 +212.8.248.197:8333 +31.10.157.171:8333 +45.84.107.200:8333 +116.75.149.83:8333 +109.93.234.55:8339 +116.74.192.64:8333 +185.246.188.149:9663 +45.144.113.253:8333 +109.139.30.102:8336 +158.220.122.39:8333 +85.244.4.208:6335 +82.118.248.205:19798 +185.220.101.24:19798 +116.202.196.52:8333 +143.244.44.175:8333 +104.244.76.237:8333 +23.137.105.248:8333 +157.230.21.198:8333 +185.207.251.50:8333 +91.236.251.138:8333 +209.141.55.26:9333 +69.218.225.129:8333 +102.90.82.109:8333 +167.179.172.173:8333 +154.216.19.10:8334 +34.217.76.29:8333 +1.4.200.149:8333 +136.42.232.7:8333 +176.126.62.152:8333 +176.52.54.126:6335 +194.14.247.36:8333 +54.180.166.112:8333 +72.50.7.43:8333 +185.220.101.181:19798 +75.128.230.115:6335 +108.35.251.240:6335 +219.117.244.105:8333 +114.216.223.123:8333 +2.94.60.118:8333 +187.87.106.4:9333 +193.32.249.217:65001 +1.156.22.158:64454 +85.249.29.39:6335 +118.166.149.5:8333 +84.66.121.155:8333 +149.19.165.195:8333 +212.171.102.227:8333 +185.209.199.95:65001 +198.98.50.112:9333 +54.65.62.127:8333 +96.21.47.54:9333 +23.234.119.118:8333 +193.189.100.206:8333 +107.172.34.196:8333 +78.46.240.210:8333 +198.102.229.253:8333 +202.53.49.202:8333 +35.79.107.85:47963 +95.217.111.35:11011 +5.188.104.245:8339 +173.216.88.59:14522 +212.241.24.147:8333 +183.4.133.120:8333 +191.204.194.52:8333 +79.40.32.207:8333 +49.13.32.144:8333 +213.55.184.49:8333 +47.128.228.87:8334 +5.255.101.131:8333 +178.165.128.167:30008 +216.24.210.151:8333 +54.251.211.75:8333 +143.105.209.32:8333 +37.120.174.180:8333 +185.220.101.50:19798 +185.246.188.74:10333 +165.227.84.200:8963 +133.167.82.173:8333 +147.81.26.71:8333 +134.101.190.231:8333 +54.178.159.239:8333 +216.8.181.249:8333 +185.129.61.8:8333 +54.250.184.95:8333 +176.52.52.4:6335 +91.141.36.118:8333 +87.78.190.15:8333 +172.56.168.149:19665 +119.111.231.247:8333 +152.37.136.203:8333 +79.195.74.220:8323 +135.181.219.10:8433 +54.219.188.176:49088 +39.190.99.154:8333 +185.40.4.127:8333 +18.197.132.221:8333 +172.56.249.36:8333 +54.39.104.128:8333 +109.213.253.48:8333 +23.129.64.198:8333 +87.249.138.133:8333 +177.140.105.178:8335 +151.68.90.113:8333 +152.53.90.71:8333 +81.183.200.65:8337 +4.189.92.202:8333 +95.216.119.109:38333 +45.143.200.32:8333 +203.12.0.126:8333 +150.221.202.248:8333 +128.73.93.121:8333 +173.249.205.122:8334 +84.153.21.72:8335 +46.114.203.255:8333 +144.76.92.36:28333 +185.31.136.173:8333 +81.183.141.187:8333 +8.217.33.31:8333 +111.251.101.180:8333 +81.154.39.95:8333 +129.224.201.176:8333 +78.47.121.92:202 +81.22.58.61:8333 +2.248.89.180:8333 +172.56.11.31:8333 +178.2.151.43:29333 +136.243.147.220:9002 +106.157.175.170:8333 +31.25.241.224:8339 +182.0.236.85:8333 +61.230.95.209:8333 +222.219.107.46:8333 +27.56.141.31:8333 +93.197.37.62:8323 +144.6.96.5:8333 +79.24.244.4:8333 +115.69.29.15:6335 +185.220.101.36:10333 +185.40.4.143:8333 +95.222.185.37:8323 +91.202.26.23:8362 +123.114.100.23:2101 +203.210.222.199:8333 +164.92.120.45:8339 +147.93.156.254:8333 +144.172.118.73:8334 +66.23.234.238:8334 +185.241.208.82:19798 +160.19.35.103:8333 +185.181.60.205:19798 +172.111.156.147:8333 +85.16.0.35:8333 +64.176.47.71:8333 +156.155.10.161:7333 +64.20.53.98:8335 +23.129.64.144:8333 +45.141.215.133:19798 +81.183.139.101:9333 +178.5.111.105:28333 +144.126.141.74:8333 +23.129.64.135:8334 +185.220.101.52:8333 +146.103.43.17:7333 +223.165.102.145:8333 +94.142.241.194:19798 +49.205.106.2:8333 +185.233.100.23:19798 +95.168.105.17:8333 +175.0.57.75:8333 +185.220.101.138:8333 +54.36.209.253:8334 +208.88.16.4:8333 +188.252.166.114:8321 +71.36.122.7:8433 +79.195.69.55:8323 +185.233.93.90:8333 +92.40.170.213:8333 +73.136.36.125:8333 +201.203.117.131:8333 +149.50.218.2:8333 +107.159.8.144:8333 +138.255.59.207:8333 +46.38.238.151:12000 +129.222.192.205:8333 +50.255.99.93:7870 +105.108.148.122:19798 +34.12.224.117:31109 +144.172.118.4:19798 +37.192.75.27:8333 +223.204.71.13:8333 +18.167.190.106:48235 +23.129.64.149:19798 +64.31.58.10:8333 +213.244.206.128:6335 +217.138.219.184:8334 +213.55.185.202:8333 +185.120.89.98:8333 +209.127.122.140:19798 +36.234.205.244:8333 +15.204.52.161:8333 +221.216.137.25:8433 +46.22.5.151:8333 +45.119.84.253:8333 +66.115.146.165:8333 +191.96.150.146:8333 +205.185.113.8:8333 +8.219.86.245:8333 +35.214.103.89:8333 +188.245.217.12:8333 +23.234.71.20:8333 +185.247.194.11:8333 +79.249.188.66:8334 +104.244.79.50:8333 +213.55.184.221:8333 +34.201.132.121:18333 +206.83.114.186:8333 +121.9.181.203:8333 +98.46.105.159:6335 +107.174.71.36:8333 +37.222.245.79:8333 +84.216.194.47:8333 +204.8.96.87:19798 +185.129.62.62:9663 +114.16.18.46:8333 +35.197.99.186:31553 +45.12.111.14:8333 +142.162.9.64:8336 +79.191.99.133:38333 +23.129.64.148:19798 +93.219.208.140:8333 +104.28.228.84:19798 +91.64.72.85:8334 +185.253.183.177:8333 +149.233.239.233:8333 +209.141.34.15:8333 +171.250.121.34:8333 +176.65.134.4:19798 +98.97.39.109:8993 +32.218.131.61:8333 +144.202.5.150:7870 +34.84.123.7:8333 +172.59.185.203:8333 +98.97.27.110:8332 +202.184.104.12:8333 +210.211.61.46:8333 +185.220.101.145:8334 +136.23.10.75:8333 +223.204.216.12:8333 +182.171.102.226:8333 +185.220.101.101:8334 +94.114.117.150:9333 +83.39.163.77:8333 +97.120.0.147:8433 +188.252.166.68:8321 +213.239.204.59:8333 +86.110.236.37:6335 +94.26.249.13:8333 +178.162.138.104:8333 +176.52.57.22:6335 +143.105.151.73:8333 +116.202.241.54:13011 +174.91.231.74:8333 +3.147.82.109:61132 +135.129.113.35:8333 +23.249.26.172:8333 +45.90.185.108:8333 +5.78.24.87:8333 +201.203.117.12:8333 +3.238.219.148:8333 +114.10.117.217:8333 +159.100.240.67:8333 +57.129.84.149:8313 +93.219.223.194:8333 +81.154.39.56:8333 +20.89.134.133:8333 +185.213.154.83:8334 +85.194.204.85:8333 +23.191.200.11:19798 +149.224.0.102:8333 +104.182.218.53:8333 +194.233.174.56:8334 +13.212.246.16:8333 +45.234.213.59:6335 +116.74.199.154:8333 +86.98.180.214:8333 +185.220.101.175:8333 +89.244.90.227:9334 +146.0.75.226:1091 +85.93.218.204:19798 +98.97.26.163:8330 +156.146.51.80:10333 +185.220.101.140:9663 +37.19.198.37:8333 +154.251.104.203:9333 +107.172.143.67:8333 +194.99.104.35:8333 +57.129.84.149:8302 +198.252.125.136:8336 +123.181.162.53:6335 +78.51.70.154:8333 +45.86.200.138:8333 +185.225.232.34:8330 +105.109.136.241:19798 +152.58.60.125:8333 +36.234.219.216:8333 +109.123.55.242:8333 +24.52.248.184:28333 +213.91.128.133:8333 +35.189.84.195:8333 +43.225.189.109:8333 +193.26.115.140:9663 +194.26.192.161:8334 +104.224.120.212:8333 +185.220.101.162:8531 +38.242.254.131:19798 +94.49.30.83:8333 +37.138.165.59:8333 +185.250.38.13:8333 +181.214.165.28:8336 +98.97.37.76:8993 +86.151.48.209:8333 +193.116.225.53:8333 +93.197.40.172:8323 +34.245.64.155:5001 +142.171.106.238:8333 +45.94.208.25:8333 +207.246.85.175:7870 +23.94.220.130:8385 +13.115.38.57:8333 +77.48.28.204:19798 +79.117.129.96:8333 +146.70.117.212:19798 +209.141.55.26:19798 +149.22.108.171:8333 +162.19.7.11:8333 +92.40.219.109:8335 +116.74.195.151:8333 +72.50.4.54:8333 +98.167.206.49:8333 +114.243.97.86:8333 +51.81.184.86:37970 +178.127.27.238:8333 +216.174.70.77:8333 +92.60.40.205:19798 +57.129.18.162:8333 +35.80.222.198:8333 +46.114.92.181:8333 +5.9.56.139:8331 +90.151.86.27:8333 +64.31.58.34:8333 +176.52.57.80:6335 +176.65.149.195:8333 +217.182.198.163:8333 +173.249.58.36:8333 +188.165.37.58:8335 +37.60.231.59:19798 +37.60.229.178:8333 +129.213.76.88:8336 +74.80.182.70:8333 +103.91.65.44:19798 +70.51.240.228:8333 +18.182.192.156:8333 +134.122.93.73:8335 +75.164.145.241:8433 +168.119.162.233:8333 +142.132.136.223:8353 +134.209.237.2:8444 +46.114.244.154:8333 +182.8.226.243:8333 +185.220.101.14:8333 +208.115.211.114:8333 +129.222.194.7:8333 +54.219.188.176:48976 +18.201.212.198:5001 +67.43.230.26:8333 +185.138.88.25:8333 +129.222.195.123:8333 +80.94.92.92:8334 +120.244.194.109:8333 +86.102.40.50:8333 +174.127.145.82:8333 +188.252.166.192:8321 +209.141.40.68:8335 +45.170.114.167:6335 +185.220.101.57:19798 +77.174.124.44:8333 +185.220.101.16:19798 +45.84.107.172:8531 +203.55.81.1:19798 +104.167.242.118:8334 +172.93.221.151:8333 +85.190.254.126:8333 +134.101.220.101:8333 +94.25.168.142:8333 +34.139.57.123:8333 +14.203.85.225:8333 +64.219.160.116:6335 +207.225.131.170:6950 +89.157.2.223:8333 +58.7.215.137:10333 +199.199.199.32:8633 +88.99.225.141:8333 +95.217.246.229:8333 +115.220.182.102:8333 +149.40.62.55:10333 +54.195.221.110:8333 +185.197.250.105:8333 +116.74.192.123:8333 +156.229.232.115:9663 +79.25.225.65:8333 +185.220.101.176:9333 +118.166.147.91:8333 +83.217.13.198:8336 +46.114.169.110:8333 +222.129.37.84:3101 +23.191.200.9:8333 +209.198.131.41:8333 +194.15.112.133:8335 +54.219.188.176:17262 +116.74.184.254:8333 +116.74.196.145:8333 +47.156.34.225:6335 +36.234.231.145:8333 +146.70.211.19:8333 +194.54.144.97:8333 +45.83.220.216:8333 +85.208.139.110:19798 +167.114.119.46:8333 +114.223.221.47:8733 +82.77.102.212:10863 +47.128.78.31:8333 +159.196.169.50:18333 +5.255.117.56:10333 +34.124.164.210:8333 +20.82.44.15:7333 +190.56.195.67:8333 +162.247.74.27:9333 +5.255.99.147:19798 +185.238.121.58:8333 +64.130.45.91:8333 +178.165.186.211:30008 +79.141.163.112:8333 +138.84.36.210:8333 +111.248.218.228:8333 +149.224.82.172:8333 +81.222.190.97:6335 +185.254.196.141:19798 +129.222.196.90:8333 +178.122.206.166:8333 +206.83.112.191:8333 +5.2.79.190:8333 +111.199.186.107:3101 +176.83.49.14:8333 +162.247.72.192:10333 +93.197.47.15:8323 +120.40.199.117:8333 +83.22.193.219:8333 +193.26.115.140:8333 +114.24.138.118:8333 +109.202.110.57:8333 +58.84.61.31:8333 +174.89.243.132:8333 +116.74.175.129:8333 +5.35.69.163:8333 +95.71.167.224:8333 +37.45.160.173:8333 +185.220.101.82:19798 +121.43.153.48:8333 +77.183.178.1:8333 +195.176.3.24:19798 +24.1.77.227:8333 +46.114.242.176:8333 +51.91.80.241:8333 +185.220.101.48:531 +122.172.87.47:8333 +194.163.156.221:8333 +73.84.169.252:8333 +46.114.170.184:8333 +103.146.203.11:19798 +73.3.203.128:8333 +83.217.13.202:8336 +167.99.60.46:8332 +62.171.137.169:8333 +185.129.62.64:8334 +194.71.227.135:8334 +146.70.194.25:8333 +172.245.178.167:8333 +111.251.68.16:8333 +98.159.36.152:8333 +65.68.45.165:6335 +173.234.17.198:8333 +23.137.248.100:19798 +212.216.140.141:8333 +89.147.108.90:19798 +91.249.95.39:8333 +151.54.241.102:8333 +206.71.158.65:19798 +39.71.151.134:8333 +46.114.219.106:8333 +109.252.70.74:8333 +81.25.170.30:8333 +176.52.57.239:6335 +49.182.78.110:8333 +98.46.105.106:6335 +211.30.131.137:8333 +23.22.205.67:18333 +46.147.150.160:8333 +195.154.167.36:8333 +49.43.43.7:8333 +111.250.63.15:8333 +60.236.93.160:8333 +157.100.198.164:6335 +45.13.225.69:9663 +54.158.91.224:8333 +31.150.127.253:8333 +45.12.52.30:8333 +185.107.57.66:19798 +171.25.193.38:8333 +95.179.139.47:8333 +213.21.32.220:8333 +104.199.92.57:46964 +188.165.77.110:9333 +98.97.41.80:8993 +46.114.88.14:8333 +157.50.174.91:8333 +45.83.104.137:10333 +89.164.36.23:8333 +72.50.4.55:8333 +39.78.148.20:8333 +185.42.170.203:19798 +93.181.204.102:8333 +104.244.79.44:19798 +73.22.179.110:8333 +47.245.28.85:8333 +77.119.211.215:8333 +95.52.114.73:18333 +195.26.231.109:8373 +88.130.80.203:6335 +52.30.206.240:8333 +81.89.56.2:52964 +107.161.89.155:8385 +185.220.101.56:10333 +119.126.168.62:8333 +95.217.73.169:8333 +188.214.104.21:8334 +5.249.38.235:8333 +125.119.157.238:8333 +162.55.230.100:8333 +194.36.145.176:8333 +39.71.151.173:8333 +35.187.240.10:8333 +60.48.93.156:8333 +80.3.166.236:8333 +49.76.141.14:8733 +185.220.101.56:9333 +77.223.102.9:8333 +91.215.89.105:8333 +82.77.81.56:8333 +81.91.189.241:8133 +23.129.64.164:7333 +193.26.115.140:19798 +169.155.251.12:8333 +103.230.184.159:8333 +91.23.153.193:8323 +149.56.16.133:8333 +18.142.36.118:8333 +5.189.186.199:8333 +149.22.108.29:8333 +148.113.16.157:8333 +143.244.42.67:7333 +35.243.80.95:8333 +64.190.76.12:19798 +182.165.86.69:8333 +62.3.53.10:8435 +87.17.89.186:8334 +88.80.26.3:19798 +155.133.22.65:8333 +190.47.66.182:8333 +46.114.246.178:8333 +92.234.19.156:28333 +86.54.28.49:19798 +169.150.218.83:10333 +191.54.39.66:8333 +185.130.47.58:9333 +195.47.238.91:8333 +51.91.18.151:19798 +117.84.219.95:8733 +152.57.43.122:8333 +61.230.72.44:8333 +35.200.60.45:8333 +13.57.191.34:8333 +149.22.108.119:8333 +197.99.36.142:8333 +61.223.221.81:8333 +23.137.254.137:8334 +84.247.187.110:8333 +84.86.187.232:8333 +23.184.48.127:10333 +75.164.137.206:8433 +156.248.8.96:8333 +203.9.210.97:19798 +34.243.233.30:5001 +45.141.215.111:8334 +85.249.25.190:8333 +176.247.45.235:8333 +193.81.233.121:39388 +174.219.126.155:8333 +217.142.22.140:8333 +176.65.149.148:19798 +101.128.96.175:6335 +31.220.78.89:8333 +52.38.59.165:8333 +117.241.248.15:8333 +23.191.200.13:8334 +185.213.80.55:8333 +3.252.227.104:50072 +185.193.88.3:8338 +95.158.207.161:45833 +46.114.212.209:8333 +89.247.166.72:8333 +35.197.99.186:31341 +185.220.101.159:10333 +138.199.21.242:8333 +188.252.164.42:8321 +79.137.68.69:8333 +171.25.193.35:19798 +43.198.67.141:8333 +18.139.1.192:8333 +47.156.147.150:8333 +85.249.31.120:8333 +213.168.89.164:8333 +93.85.162.78:8333 +114.223.15.143:8733 +201.206.180.3:8333 +23.129.64.217:9333 +34.172.151.203:8333 diff --git a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp index c94932c1..1316e017 100644 --- a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp +++ b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp @@ -76,8 +76,9 @@ struct KB_API block_chain { // ORGANIZERS (Core blockchain operations) // ========================================================================= + /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable organize(block_const_ptr block); + ::asio::awaitable organize(block_const_ptr block, bool headers_pre_validated = false); [[nodiscard]] ::asio::awaitable organize(transaction_const_ptr tx); @@ -186,6 +187,7 @@ struct KB_API block_chain { [[nodiscard]] std::expected, database::result_code> get_transaction_position( hash_digest const& hash, bool require_confirmed) const; + [[nodiscard]] bool header_exists(hash_digest const& block_hash) const; [[nodiscard]] bool block_exists(hash_digest const& block_hash) const; // ========================================================================= diff --git a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp index cb0e78ae..369f3bd9 100644 --- a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp @@ -50,8 +50,9 @@ struct KB_API block_organizer { bool stop(); /// Organize a block - coroutine version + /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable organize(block_const_ptr block); + ::asio::awaitable organize(block_const_ptr block, bool headers_pre_validated = false); [[nodiscard]] block_broadcaster::channel_ptr subscribe(); diff --git a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp index b84cfe9c..34105a96 100644 --- a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp @@ -8,10 +8,9 @@ #include #include #include -#include -#include #include +#include #include #include #include @@ -19,62 +18,40 @@ namespace kth::blockchain { -// Forward declaration -struct block_chain; - /// Result of adding headers to the organizer struct header_organize_result { code error; size_t headers_added{0}; - size_t cache_size{0}; - size_t cache_memory_bytes{0}; -}; - -/// Configuration for the header cache -struct header_cache_config { - /// Maximum memory to use for header cache (bytes) - /// Default: 256 MB - size_t max_cache_memory = 256 * 1024 * 1024; - - /// Memory overhead factor (for allocator overhead) - /// Default: 1.12 (~12% overhead for jemalloc) - double memory_overhead = 1.12; - - /// Auto-flush when cache reaches this percentage of max - /// Default: 0.9 (90%) - double auto_flush_threshold = 0.9; + size_t index_size{0}; + size_t index_memory_bytes{0}; }; /// Header organizer for headers-first sync. -/// Validates and caches headers during initial block download (IBD). +/// Validates headers and stores them in the header_index. /// /// ARCHITECTURE: /// ------------- -/// The organizer maintains an in-memory cache of validated headers. -/// Headers are validated as they arrive and stored in the cache. -/// When flush() is called (or cache is full), headers are persisted to DB. +/// The organizer validates headers as they arrive and stores them +/// in the header_index (SoA structure with O(1) hash lookup and +/// O(log n) ancestor lookup via skip pointers). /// -/// This design allows: -/// 1. Fast header validation without DB round-trips -/// 2. Batch DB writes for efficiency -/// 3. Memory-aware caching with configurable limits +/// The header_index is owned by block_chain and passed by reference. /// /// THREAD SAFETY: /// -------------- -/// All public methods are thread-safe (protected by mutex). +/// Thread-safe through header_index's concurrent_flat_map. struct KB_API header_organizer { using ptr = std::shared_ptr; + using index_t = header_index::index_t; /// Construct a header organizer. - /// @param[in] chain Reference to the blockchain. + /// @param[in] index Reference to the header index (owned by block_chain). /// @param[in] settings Blockchain settings. /// @param[in] network The network type. - /// @param[in] config Cache configuration. - header_organizer(block_chain& chain, settings const& settings, - domain::config::network network, - header_cache_config config = {}); + header_organizer(header_index& index, settings const& settings, + domain::config::network network); - ~header_organizer(); + ~header_organizer() = default; // Non-copyable header_organizer(header_organizer const&) = delete; @@ -83,109 +60,86 @@ struct KB_API header_organizer { bool start(); bool stop(); - /// Initialize the organizer with current chain state. - /// Must be called before adding headers. - /// @param[in] current_height Current header height in DB. - /// @param[in] current_tip_hash Hash of current header tip. - /// @param[in] expected_headers Estimated number of headers to sync (for pre-allocation). - void initialize(size_t current_height, hash_digest const& current_tip_hash, - size_t expected_headers = 0); + /// Sync tip state from the header index. + /// Call after header_index has been initialized (e.g., with genesis). + void sync_tip(); /// Add a batch of headers to the organizer. - /// Validates all headers and adds valid ones to the cache. - /// May auto-flush to DB if cache is getting full. + /// Validates all headers and adds valid ones to the index. /// @param[in] headers The headers to add. /// @return Result with error code and statistics. [[nodiscard]] header_organize_result add_headers(domain::message::header::list const& headers); - /// Flush all cached headers to the database. - /// @return error::success or the storage error. - [[nodiscard]] - code flush(); - - /// Get the block hashes of all cached headers. - /// Useful for requesting blocks after headers are synced. - [[nodiscard]] - std::vector get_cached_hashes() const; - - /// Clear the cache without flushing to DB. - /// Use with caution - discards unwritten headers. - void clear_cache(); - // ========================================================================= - // State queries + // Index Access // ========================================================================= - /// Get the current header tip height (DB + cache). + /// Get the header index. [[nodiscard]] - size_t header_height() const; + header_index& index() { return index_; } - /// Get the hash of the header tip. [[nodiscard]] - hash_digest header_tip_hash() const; + header_index const& index() const { return index_; } - /// Get the number of headers in cache. + /// Find a header by hash. [[nodiscard]] - size_t cache_size() const; + index_t find(hash_digest const& hash) const { return index_.find(hash); } - /// Get estimated memory usage of the cache. + /// Check if a header exists. [[nodiscard]] - size_t cache_memory() const; + bool contains(hash_digest const& hash) const { return index_.contains(hash); } + + // ========================================================================= + // State queries + // ========================================================================= - /// Check if cache has pending headers. + /// Get the current tip index. [[nodiscard]] - bool has_pending() const; + index_t tip_index() const { return tip_index_; } - /// Calculate optimal batch size based on available memory. - /// @param[in] items_needed Total headers we want to sync. - /// @return Optimal number of headers to cache. + /// Get the current header tip height. [[nodiscard]] - size_t calculate_optimal_cache_size(size_t items_needed) const; + int32_t header_height() const; -protected: + /// Get the hash of the header tip. [[nodiscard]] - bool stopped() const { - return stopped_; - } + hash_digest const& header_tip_hash() const { return tip_hash_; } -private: - // Validate a single header against expected previous + /// Get the timestamp of the header tip. + /// Used for BCHN-style progress calculation. [[nodiscard]] - code validate(domain::chain::header const& header, size_t height, - hash_digest const& previous) const; + uint32_t tip_timestamp() const; - // Estimate memory for a single header + /// Get the number of headers in the index. [[nodiscard]] - static size_t estimated_header_size(); + size_t size() const { return index_.size(); } - // Internal cache_memory without lock (caller must hold mutex_) + /// Get estimated memory usage. [[nodiscard]] - size_t cache_memory_impl() const; + size_t memory_usage() const { return index_.memory_usage(); } - // Internal flush without lock (caller must hold mutex_) +protected: [[nodiscard]] - code flush_impl(); + bool stopped() const { return stopped_; } - // Check if we should auto-flush +private: + // Validate a single header with full chain-state validation + // Includes: PoW check, difficulty, checkpoint, version, MTP [[nodiscard]] - bool should_auto_flush() const; + code validate_full(domain::chain::header const& header, + hash_digest const& hash, + int32_t height, + header_index::index_t parent_idx) const; // Members - block_chain& chain_; + header_index& index_; std::atomic stopped_{false}; validate_header validator_; - header_cache_config config_; - mutable std::mutex mutex_; - - // Chain state (protected by mutex_) - size_t db_header_height_{0}; // Height of headers in DB - hash_digest db_tip_hash_{null_hash}; // Hash of DB header tip - // Cache state (protected by mutex_) - domain::chain::header::list header_cache_; - std::vector hash_cache_; // Parallel cache of hashes - hash_digest cache_tip_hash_{null_hash}; + // Current tip state + index_t tip_index_{header_index::null_index}; + hash_digest tip_hash_{null_hash}; }; } // namespace kth::blockchain diff --git a/src/blockchain/include/kth/blockchain/settings.hpp b/src/blockchain/include/kth/blockchain/settings.hpp index 8cff1e78..79d4cd5b 100644 --- a/src/blockchain/include/kth/blockchain/settings.hpp +++ b/src/blockchain/include/kth/blockchain/settings.hpp @@ -32,6 +32,8 @@ struct KB_API settings { uint32_t notify_limit_hours = 24; uint32_t reorganization_limit = 256; infrastructure::config::checkpoint::list checkpoints; + infrastructure::config::checkpoint::list checkpoints_sorted; // Pre-sorted by height + size_t max_checkpoint_height = 0; // Pre-computed max bool fix_checkpoints = true; bool allow_collisions = true; bool easy_blocks = false; diff --git a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp index 800b6fe6..c8ad1b15 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp @@ -41,15 +41,32 @@ struct KB_API validate_block { void start(); void stop(); + /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable check(block_const_ptr block) const; + ::asio::awaitable check(block_const_ptr block, bool headers_pre_validated = false) const; + /// @param headers_pre_validated If true, use accept_body() to skip header validation [[nodiscard]] - ::asio::awaitable accept(branch::const_ptr branch) const; + ::asio::awaitable accept(branch::const_ptr branch, bool headers_pre_validated = false) const; [[nodiscard]] ::asio::awaitable connect(branch::const_ptr branch) const; + // ========================================================================= + // Static validation functions (pure, no side effects) + // These replace the accept/connect methods that were in block_basis. + // ========================================================================= + + /// Validate block body against chain state (skip header validation). + /// Validates: block size, transaction ordering, coinbase, finality. + /// @param block The block to validate. + /// @param state The chain state for context. + /// @return error::success or validation error. + [[nodiscard]] + static code accept_block_body( + domain::chain::block const& block, + domain::chain::chain_state const& state); + protected: [[nodiscard]] bool stopped() const { diff --git a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp index f7337579..eebf11b5 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp @@ -7,8 +7,10 @@ #include #include +#include #include +#include #include #include @@ -35,6 +37,10 @@ struct KB_API validate_header { /// @param[in] network The network type (mainnet, testnet, etc). validate_header(settings const& settings, domain::config::network network); + /// Access the settings. + [[nodiscard]] + settings const& chain_settings() const { return settings_; } + /// Context-free validation (PoW + timestamp). /// Validates: /// - Proof of work is valid for the claimed difficulty (bits) @@ -68,6 +74,67 @@ struct KB_API validate_header { code validate(domain::chain::header const& header, size_t height, hash_digest const& previous) const; + // ========================================================================= + // Full validation with header_index (for headers-first sync) + // ========================================================================= + + /// Full accept validation using header_index to build chain_state. + /// This performs complete header validation including: + /// - Chain continuity (previous block hash) + /// - Checkpoint validation + /// - Difficulty check (work_required) + /// - Version check (minimum_version) + /// - Median time past check + /// + /// @param[in] header The header to validate. + /// @param[in] hash The header's hash. + /// @param[in] height The height of this header. + /// @param[in] parent_idx Index of parent header in the index. + /// @param[in] index The header index containing historical data. + /// @return error::success or the validation error. + [[nodiscard]] + code accept_full(domain::chain::header const& header, + hash_digest const& hash, + size_t height, + header_index::index_t parent_idx, + header_index const& index) const; + + /// Build chain_state::data from header_index for a given height. + /// This collects the historical bits, versions, and timestamps needed + /// to construct a chain_state for validation. + /// + /// @param[in] height The target height. + /// @param[in] header The header at target height. + /// @param[in] hash The header's hash. + /// @param[in] parent_idx Index of parent header in the index. + /// @param[in] index The header index containing historical data. + /// @return chain_state::data populated from the index, or error code on failure. + [[nodiscard]] + std::expected build_chain_state_data( + size_t height, + domain::chain::header const& header, + hash_digest const& hash, + header_index::index_t parent_idx, + header_index const& index) const; + + // ========================================================================= + // Static validation functions (pure, no side effects) + // These can be called without a validate_header instance when chain_state + // is already available. + // ========================================================================= + + /// Validate header against chain state. + /// Validates: difficulty, checkpoint, version, MTP. + /// @param header The header to validate. + /// @param hash The header hash. + /// @param state The chain state for context. + /// @return error::success or validation error. + [[nodiscard]] + static code accept_header( + domain::chain::header const& header, + hash_digest const& hash, + domain::chain::chain_state const& state); + /// Check if a height is under checkpoint protection. /// Headers under checkpoint can skip some validation. [[nodiscard]] @@ -90,8 +157,24 @@ struct KB_API validate_header { [[nodiscard]] size_t last_checkpoint_height() const; + /// Collect historical data (bits, versions, timestamps) from header_index. + /// Single traversal for efficiency. + [[nodiscard]] + std::expected collect_historical_data( + domain::chain::chain_state::map const& map, + header_index::index_t parent_idx, + header_index const& index) const; + +#if defined(KTH_CURRENCY_BCH) + /// Get the ASERT anchor block info for the network. + [[nodiscard]] + domain::chain::chain_state::assert_anchor_block_info_t get_asert_anchor_block() const; +#endif + // Configuration + settings const& settings_; checkpoint_list const checkpoints_; + uint32_t const configured_forks_; domain::config::network const network_; bool const retarget_; // Whether PoW retargeting is enabled (mainnet=true) }; diff --git a/src/blockchain/src/pools/block_organizer.cpp b/src/blockchain/src/pools/block_organizer.cpp index cd418fcf..a7d01b7a 100644 --- a/src/blockchain/src/pools/block_organizer.cpp +++ b/src/blockchain/src/pools/block_organizer.cpp @@ -83,7 +83,7 @@ bool block_organizer::stop() { // Organize sequence. //----------------------------------------------------------------------------- -::asio::awaitable block_organizer::organize(block_const_ptr block) { +::asio::awaitable block_organizer::organize(block_const_ptr block, bool headers_pre_validated) { // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_high_priority(); //TODO: is it possible to remove this mutex? @@ -101,7 +101,8 @@ ::asio::awaitable block_organizer::organize(block_const_ptr block) { } // Checks that are independent of chain state. - auto ec = co_await validator_.check(block); + // For headers-first sync, skip header validation since headers were already validated. + auto ec = co_await validator_.check(block, headers_pre_validated); if (stopped()) { mutex_.unlock_high_priority(); @@ -134,7 +135,8 @@ ::asio::awaitable block_organizer::organize(block_const_ptr block) { } // Checks that are dependent on chain state and prevouts. - ec = co_await validator_.accept(branch); + // For headers-first sync, use accept_body() to skip header validation. + ec = co_await validator_.accept(branch, headers_pre_validated); if (stopped()) { mutex_.unlock_high_priority(); diff --git a/src/blockchain/src/pools/header_organizer.cpp b/src/blockchain/src/pools/header_organizer.cpp index ee828be9..af0851fb 100644 --- a/src/blockchain/src/pools/header_organizer.cpp +++ b/src/blockchain/src/pools/header_organizer.cpp @@ -4,38 +4,26 @@ #include -#include +#include + +#include -#include #include #include #include -#include namespace kth::blockchain { -using namespace kth::domain::chain; - // ============================================================================= -// Construction / Destruction +// Construction // ============================================================================= -header_organizer::header_organizer(block_chain& chain, settings const& settings, - domain::config::network network, - header_cache_config config) - : chain_(chain) +header_organizer::header_organizer(header_index& index, settings const& settings, + domain::config::network network) + : index_(index) , validator_(settings, network) - , config_(config) {} -header_organizer::~header_organizer() { - // Attempt to flush any pending headers on destruction - if (has_pending()) { - spdlog::warn("[header_organizer] Destroying with {} unflushed headers", - header_cache_.size()); - } -} - // ============================================================================= // Lifecycle // ============================================================================= @@ -54,24 +42,16 @@ bool header_organizer::stop() { // Initialization // ============================================================================= -void header_organizer::initialize(size_t current_height, hash_digest const& current_tip_hash, - size_t expected_headers) { - std::lock_guard lock(mutex_); - - db_header_height_ = current_height; - db_tip_hash_ = current_tip_hash; - cache_tip_hash_ = current_tip_hash; - - // Pre-allocate cache if we know how many headers to expect - if (expected_headers > 0) { - auto const optimal_size = calculate_optimal_cache_size(expected_headers); - header_cache_.reserve(optimal_size); - hash_cache_.reserve(optimal_size); - - spdlog::info("[header_organizer] Initialized: DB height {}, cache pre-allocated for {} headers", - current_height, optimal_size); - } else { - spdlog::info("[header_organizer] Initialized: DB height {}", current_height); +void header_organizer::sync_tip() { + // Sync tip from the header index (assumes index is already initialized) + auto const size = index_.size(); + if (size > 0) { + // For now, assume tip is the last added entry (index size - 1) + // TODO(fernando): properly track the actual chain tip when we support forks + tip_index_ = index_t(size - 1); + tip_hash_ = index_.get_hash(tip_index_); + spdlog::info("[header_organizer] Synced tip: index {}, hash {}", + tip_index_, encode_hash(tip_hash_)); } } @@ -92,25 +72,27 @@ header_organize_result header_organizer::add_headers(domain::message::header::li return result; } - std::lock_guard lock(mutex_); - spdlog::debug("[header_organizer] add_headers() called with {} headers", headers.size()); - // Current tip is either from cache or from DB - hash_digest prev_hash = cache_tip_hash_; - size_t height = db_header_height_ + header_cache_.size() + 1; + // Current tip for validation + hash_digest prev_hash = tip_hash_; + int32_t height = index_.get_height(tip_index_) + 1; - spdlog::debug("[header_organizer] Starting validation loop at height {}, cache_tip_hash: {}", - height, encode_hash(cache_tip_hash_)); - - if (!headers.empty()) { - spdlog::debug("[header_organizer] First header previous_block_hash: {}", - encode_hash(headers.front().previous_block_hash())); - } + spdlog::debug("[header_organizer] Starting validation at height {}, tip_hash: {}", + height, encode_hash(tip_hash_)); for (auto const& header : headers) { - // Validate header - auto const ec = validate(header, height, prev_hash); + // Compute hash first (needed for validation) + KTH_STATS_TIME_START(hash); + auto const hash = header.hash(); + KTH_STATS_TIME_END(global_sync_stats(), hash, hash_time_ns, hash_calls); + + // Validate header with full chain-state validation + // This includes: PoW check, difficulty, checkpoint, version, MTP + KTH_STATS_TIME_START(validate); + auto const ec = validate_full(header, hash, height, tip_index_); + KTH_STATS_TIME_END(global_sync_stats(), validate, validate_time_ns, validate_calls); + if (ec) { spdlog::debug("[header_organizer] Header validation failed at height {}: {}", height, ec.message()); @@ -118,195 +100,83 @@ header_organize_result header_organizer::add_headers(domain::message::header::li break; } - // Compute hash and add to caches - auto const hash = header.hash(); - header_cache_.push_back(header); - hash_cache_.push_back(hash); - - prev_hash = hash; - cache_tip_hash_ = hash; - ++height; - ++result.headers_added; - - // Log progress every 500 headers - if (result.headers_added % 500 == 0) { - spdlog::debug("[header_organizer] Validated {} headers...", result.headers_added); + KTH_STATS_TIME_START(index_add); + auto const add_result = index_.add(hash, header); + KTH_STATS_TIME_END(global_sync_stats(), index_add, index_add_time_ns, index_add_calls); + + if (add_result.inserted) { + tip_index_ = add_result.index; + tip_hash_ = hash; + prev_hash = hash; + ++height; + ++result.headers_added; + + // Mark as valid header + index_.add_status(add_result.index, header_status::valid_header); + + if (add_result.capacity_warning) { + spdlog::warn("[header_organizer] Header index at 95% capacity!"); + } + } else { + // Header already existed - this shouldn't happen in normal sync + spdlog::debug("[header_organizer] Header already exists at index {}", + add_result.index); } - } - - spdlog::debug("[header_organizer] Validation complete: {} headers added", result.headers_added); - result.cache_size = header_cache_.size(); - result.cache_memory_bytes = cache_memory_impl(); - - // Check if we should auto-flush - if (should_auto_flush()) { - spdlog::info("[header_organizer] Cache threshold reached ({} headers, {} MB), auto-flushing", - header_cache_.size(), - result.cache_memory_bytes / (1024 * 1024)); - - auto const flush_ec = flush_impl(); // Use _impl to avoid deadlock (we already hold mutex_) - if (flush_ec && result.error == error::success) { - result.error = flush_ec; - } - } - - return result; -} - -// ============================================================================= -// Flush to Database -// ============================================================================= - -code header_organizer::flush() { - std::lock_guard lock(mutex_); - return flush_impl(); -} - -// Internal version without lock (caller must hold mutex_) -code header_organizer::flush_impl() { - if (header_cache_.empty()) { - return error::success; + // Log progress every 1000 headers + // if (result.headers_added > 0 && result.headers_added % 1000 == 0) { + // spdlog::debug("[header_organizer] Validated {} headers, height {}...", + // result.headers_added, height - 1); + // } } - auto const start_height = db_header_height_ + 1; - auto const count = header_cache_.size(); - - spdlog::debug("[header_organizer] Flushing {} headers to DB starting at height {}", - count, start_height); - - // Store all headers in batch - auto const ec = chain_.organize_headers_batch(header_cache_, start_height); - if (ec && ec != error::duplicate_block) { - spdlog::warn("[header_organizer] Failed to flush headers batch: {}", ec.message()); - return ec; - } - - // Update DB state - db_header_height_ = start_height + count - 1; - db_tip_hash_ = cache_tip_hash_; - - // Clear cache - header_cache_.clear(); - hash_cache_.clear(); + spdlog::debug("[header_organizer] Validation complete: {} headers added, total size {}", + result.headers_added, index_.size()); - spdlog::debug("[header_organizer] Flush complete, DB height now {}", db_header_height_); + result.index_size = index_.size(); + result.index_memory_bytes = index_.memory_usage(); - return error::success; -} - -// ============================================================================= -// Cache Access -// ============================================================================= - -std::vector header_organizer::get_cached_hashes() const { - std::lock_guard lock(mutex_); - return hash_cache_; -} - -void header_organizer::clear_cache() { - std::lock_guard lock(mutex_); - - header_cache_.clear(); - header_cache_.shrink_to_fit(); - hash_cache_.clear(); - hash_cache_.shrink_to_fit(); - - // Reset cache tip to DB tip - cache_tip_hash_ = db_tip_hash_; + return result; } // ============================================================================= // State Queries // ============================================================================= -size_t header_organizer::header_height() const { - std::lock_guard lock(mutex_); - return db_header_height_ + header_cache_.size(); -} - -hash_digest header_organizer::header_tip_hash() const { - std::lock_guard lock(mutex_); - return cache_tip_hash_; -} - -size_t header_organizer::cache_size() const { - std::lock_guard lock(mutex_); - return header_cache_.size(); -} - -size_t header_organizer::cache_memory() const { - std::lock_guard lock(mutex_); - return cache_memory_impl(); -} - -// Internal version without lock (caller must hold mutex_) -size_t header_organizer::cache_memory_impl() const { - auto const header_size = estimated_header_size(); - auto const hash_size = sizeof(hash_digest); - return static_cast( - (header_cache_.size() * header_size + hash_cache_.size() * hash_size) - * config_.memory_overhead - ); -} - -bool header_organizer::has_pending() const { - std::lock_guard lock(mutex_); - return !header_cache_.empty(); -} - -// ============================================================================= -// Memory Estimation -// ============================================================================= - -size_t header_organizer::calculate_optimal_cache_size(size_t items_needed) const { - // Header size + hash size per item - auto const item_size = estimated_header_size() + sizeof(hash_digest); - - auto const available = kth::get_available_system_memory(); - if (available == 0) { - // Fallback: use config max or reasonable default - auto const max_items = config_.max_cache_memory / item_size; - return std::min(items_needed, max_items); +int32_t header_organizer::header_height() const { + if (tip_index_ == header_index::null_index) { + return -1; // No headers yet (only genesis) } - - // Memory per item including overhead - auto const bytes_per_item = static_cast(item_size * config_.memory_overhead); - - // Use configured max or fraction of available memory (whichever is smaller) - auto const memory_fraction = available / 2; // Use at most 50% of available - auto const usable_memory = std::min(config_.max_cache_memory, memory_fraction); - - // Calculate how many items we can fit - auto const max_items = bytes_per_item > 0 ? usable_memory / bytes_per_item : 0; - - return std::min(items_needed, max_items); + return index_.get_height(tip_index_); } -size_t header_organizer::estimated_header_size() { - // Header base size: version(4) + prev_hash(32) + merkle(32) + time(4) + bits(4) + nonce(4) = 80 bytes - // Plus std::vector overhead and alignment - return 80 + 48; // ~128 bytes estimated with overhead +uint32_t header_organizer::tip_timestamp() const { + if (tip_index_ == header_index::null_index) { + return 0; + } + return index_.get_timestamp(tip_index_); } // ============================================================================= -// Internal Helpers +// Validation // ============================================================================= -code header_organizer::validate(domain::chain::header const& header, size_t height, - hash_digest const& previous) const { - return validator_.validate(header, height, previous); -} - -bool header_organizer::should_auto_flush() const { - // Note: caller must hold mutex_ - auto const current_memory = static_cast( - (header_cache_.size() * estimated_header_size() + hash_cache_.size() * sizeof(hash_digest)) - * config_.memory_overhead - ); +code header_organizer::validate_full(domain::chain::header const& header, + hash_digest const& hash, + int32_t height, + header_index::index_t parent_idx) const { + // First do context-free check (PoW, timestamp not too far in future) + // Skip PoW check if under checkpoint (trusted headers) + if (!validator_.is_under_checkpoint(size_t(height))) { + auto const ec = validator_.check(header); + if (ec) { + return ec; + } + } - auto const threshold = static_cast(config_.max_cache_memory * config_.auto_flush_threshold); - return current_memory >= threshold; + // Then do full accept validation with chain_state built from header_index + // This validates: difficulty, checkpoint, version, MTP + return validator_.accept_full(header, hash, size_t(height), parent_idx, index_); } } // namespace kth::blockchain diff --git a/src/blockchain/src/populate/populate_chain_state.cpp b/src/blockchain/src/populate/populate_chain_state.cpp index eca77ff9..77d14824 100644 --- a/src/blockchain/src/populate/populate_chain_state.cpp +++ b/src/blockchain/src/populate/populate_chain_state.cpp @@ -36,7 +36,7 @@ populate_chain_state::populate_chain_state(block_chain const& chain, settings co settings_(settings), #endif //KTH_CURRENCY_BCH configured_forks_(settings.enabled_forks()) - , checkpoints_(infrastructure::config::checkpoint::sort(settings.checkpoints)) + , checkpoints_(settings.checkpoints_sorted) , network_(network) , chain_(chain) {} diff --git a/src/blockchain/src/settings.cpp b/src/blockchain/src/settings.cpp index 1d4e5c20..a5dbc056 100644 --- a/src/blockchain/src/settings.cpp +++ b/src/blockchain/src/settings.cpp @@ -70,6 +70,12 @@ settings::settings(domain::config::network net) { } checkpoints = domain::config::default_checkpoints(net); + + // Pre-compute sorted list and max height + checkpoints_sorted = infrastructure::config::checkpoint::sort(checkpoints); + if (!checkpoints_sorted.empty()) { + max_checkpoint_height = checkpoints_sorted.back().height(); + } } uint32_t settings::enabled_forks() const { diff --git a/src/blockchain/src/validate/validate_block.cpp b/src/blockchain/src/validate/validate_block.cpp index 395cbe62..253ae417 100644 --- a/src/blockchain/src/validate/validate_block.cpp +++ b/src/blockchain/src/validate/validate_block.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,7 @@ void validate_block::stop() { //----------------------------------------------------------------------------- // These checks are context free. -::asio::awaitable validate_block::check(block_const_ptr block) const { +::asio::awaitable validate_block::check(block_const_ptr block, bool headers_pre_validated) const { // The block hasn't been checked yet. if (block->transactions().empty()) { co_return error::success; @@ -108,6 +109,11 @@ ::asio::awaitable validate_block::check(block_const_ptr block) const { } // Run context free checks, sets time internally. + // For headers-first sync, skip header validation (PoW, timestamp) since + // headers were already validated during header sync. + if (headers_pre_validated) { + co_return block->check_body(); + } co_return block->check(); } @@ -130,7 +136,7 @@ code validate_block::check_block_bucket(block_const_ptr block, size_t bucket, si //----------------------------------------------------------------------------- // These checks require chain state, and block state if not under checkpoint. -::asio::awaitable validate_block::accept(branch::const_ptr branch) const { +::asio::awaitable validate_block::accept(branch::const_ptr branch, bool headers_pre_validated) const { auto const block = branch->top(); KTH_ASSERT(block); @@ -155,30 +161,39 @@ ::asio::awaitable validate_block::accept(branch::const_ptr branch) const { co_return populate_ec; } - auto const height = block->validation.state->height(); + auto const& state = *block->validation.state; // Run contextual block non-tx checks (sets start time). - auto const error_code = block->accept(false); + // For headers-first sync, skip header validation since headers were + // already validated during header sync. + if ( ! headers_pre_validated) { + // Full validation: validate header first + auto const header_ec = validate_header::accept_header(block->header(), block->hash(), state); + if (header_ec) { + co_return header_ec; + } + } - if (error_code) { - co_return error_code; + // Validate block body (same for both cases) + auto const body_ec = accept_block_body(*block, state); + if (body_ec) { + co_return body_ec; } auto const sigops = std::make_shared(0); - auto const state = block->validation.state; - KTH_ASSERT(state); + #if defined(KTH_CURRENCY_BCH) bool const bip141 = false; #else - auto const bip141 = state->is_enabled(domain::machine::rule_fork::bip141_rule); + auto const bip141 = state.is_enabled(domain::machine::rule_fork::bip141_rule); #endif - if (state->is_under_checkpoint()) { + if (state.is_under_checkpoint()) { co_return error::success; } auto const count = block->transactions().size(); - auto const bip16 = state->is_enabled(domain::machine::rule_fork::bip16_rule); + auto const bip16 = state.is_enabled(domain::machine::rule_fork::bip16_rule); auto const buckets = std::min(threads_, count); KTH_ASSERT(buckets != 0); @@ -404,4 +419,95 @@ void validate_block::dump(code const& ec, transaction const& tx, uint32_t input_ prevout.validation.cache.value(), tx_hash, input_index, encode_base16(tx.to_data(true))); } +// ============================================================================= +// Static validation functions (pure, no side effects) +// These replace the accept/connect methods that were in block_basis. +// ============================================================================= + +code validate_block::accept_block_body( + domain::chain::block const& block, + domain::chain::chain_state const& state) { + + auto const& header = block.header(); + auto const block_size = block.serialized_size(); + + auto const bip16 = state.is_enabled(domain::machine::rule_fork::bip16_rule); + auto const bip34 = state.is_enabled(domain::machine::rule_fork::bip34_rule); + auto const bip113 = state.is_enabled(domain::machine::rule_fork::bip113_rule); + auto const bip141 = false; // No segwit + + // Block size validation +#if defined(KTH_CURRENCY_BCH) + if (state.is_lobachevski_enabled()) { + if (block_size > state.dynamic_max_block_size()) { + return error::block_size_limit; + } + } else if (state.is_pythagoras_enabled()) { + if (block_size > static_max_block_size(state.network())) { + return error::block_size_limit; + } + } else { + if (block_size > max_block_size::mainnet_old) { + return error::block_size_limit; + } + } +#else + if (block_size > max_block_size::mainnet_old) { + return error::block_size_limit; + } +#endif + + // Under checkpoint: Only verify merkle root (done in check_body) + if (state.is_under_checkpoint()) { + return error::success; + } + + // Transaction ordering check +#if defined(KTH_CURRENCY_BCH) + if (state.is_euclid_enabled()) { + if ( ! block.is_canonical_ordered()) { + return error::non_canonical_ordered; + } + } else { + if (block.is_forward_reference()) { + return error::forward_reference; + } + } +#else + if (block.is_forward_reference()) { + return error::forward_reference; + } +#endif + + // Coinbase script height check (BIP34) + if (bip34 && !block.is_valid_coinbase_script(state.height())) { + return error::coinbase_height_mismatch; + } + + // Coinbase claim check + if ( ! block.is_valid_coinbase_claim(state.height())) { + return error::coinbase_value_limit; + } + + // Finality check + auto const block_time = bip113 ? state.median_time_past() : header.timestamp(); + if ( ! block.is_final(state.height(), block_time)) { + return error::block_non_final; + } + + // Sigops check (for non-Fermat BCH or BTC/LTC) +#if defined(KTH_CURRENCY_BCH) + if ( ! state.is_fermat_enabled()) { +#endif + size_t const allowed_sigops = get_allowed_sigops(block_size); + if (block.signature_operations(bip16, bip141) > allowed_sigops) { + return error::block_embedded_sigop_limit; + } +#if defined(KTH_CURRENCY_BCH) + } +#endif + + return error::success; +} + } // namespace kth::blockchain diff --git a/src/blockchain/src/validate/validate_header.cpp b/src/blockchain/src/validate/validate_header.cpp index 2ee02e78..75ecffb4 100644 --- a/src/blockchain/src/validate/validate_header.cpp +++ b/src/blockchain/src/validate/validate_header.cpp @@ -5,9 +5,11 @@ #include #include +#include #include +#include #include #include @@ -17,7 +19,9 @@ using namespace kth::domain::chain; using namespace kth::infrastructure::config; validate_header::validate_header(settings const& settings, domain::config::network network) - : checkpoints_(checkpoint::sort(settings.checkpoints)) + : settings_(settings) + , checkpoints_(settings.checkpoints_sorted) + , configured_forks_(settings.enabled_forks()) , network_(network) , retarget_(network != domain::config::network::regtest) {} @@ -125,4 +129,314 @@ size_t validate_header::last_checkpoint_height() const { return checkpoints_.back().height(); } +// ============================================================================= +// Full validation with header_index +// ============================================================================= + +std::expected validate_header::collect_historical_data( + chain_state::map const& map, + header_index::index_t parent_idx, + header_index const& index) const { + + chain_state::data data{}; + + // Resize all containers + data.bits.ordered.resize(map.bits.count); + data.version.ordered.resize(map.version.count); + data.timestamp.ordered.resize(map.timestamp.count); + + // Calculate maximum steps needed + auto const max_count = std::max({map.bits.count, map.version.count, map.timestamp.count}); + + if (max_count == 0) { + return data; + } + + // Single traversal collecting all data types + auto idx = parent_idx; + for (size_t step = 0; step < max_count && idx != header_index::null_index; ++step) { + // Collect bits if still needed (store in reverse order) + if (step < map.bits.count) { + data.bits.ordered[map.bits.count - 1 - step] = index.get_bits(idx); + } + + // Collect versions if still needed + if (step < map.version.count) { + data.version.ordered[map.version.count - 1 - step] = index.get_version(idx); + } + + // Collect timestamps if still needed + if (step < map.timestamp.count) { + data.timestamp.ordered[map.timestamp.count - 1 - step] = index.get_timestamp(idx); + } + + idx = index.get_parent_index(idx); + } + + // Verify we collected enough data + if (idx == header_index::null_index) { + // Check if we collected all required data + auto const parent_height = index.get_height(parent_idx); + if (parent_height + 1 < static_cast(max_count)) { + spdlog::warn("[validate_header] collect_historical_data: insufficient chain depth, " + "need {} but only have {}", max_count, parent_height + 1); + return std::unexpected(error::operation_failed); + } + } + + // Collect retarget timestamp if needed (separate lookup via skip pointers) + if (map.timestamp_retarget != chain_state::map::unrequested) { + auto const retarget_height = static_cast(map.timestamp_retarget); + auto retarget_idx = index.get_ancestor(parent_idx, retarget_height); + + if (retarget_idx == header_index::null_index) { + spdlog::warn("[validate_header] collect_historical_data: could not find retarget ancestor at height {}", + retarget_height); + return std::unexpected(error::operation_failed); + } + +#if defined(KTH_CURRENCY_LTC) + // Litecoin uses (retarget - 1) for some reason + if (retarget_height > 0) { + retarget_idx = index.get_parent_index(retarget_idx); + } +#endif + data.timestamp.retarget = index.get_timestamp(retarget_idx); + } + + return data; +} + +#if defined(KTH_CURRENCY_BCH) +chain_state::assert_anchor_block_info_t validate_header::get_asert_anchor_block() const { + using namespace kth::domain; + + auto const height = network_map(network_ + , mainnet_asert_anchor_block_height + , testnet_asert_anchor_block_height + , size_t(0) + , testnet4_asert_anchor_block_height + , scalenet_asert_anchor_block_height + , chipnet_asert_anchor_block_height + ); + + auto const ancestor_time = network_map(network_ + , mainnet_asert_anchor_block_ancestor_time + , testnet_asert_anchor_block_ancestor_time + , size_t(0) + , testnet4_asert_anchor_block_ancestor_time + , scalenet_asert_anchor_block_ancestor_time + , chipnet_asert_anchor_block_ancestor_time + ); + + uint32_t const bits = network_map(network_ + , mainnet_asert_anchor_block_bits + , testnet_asert_anchor_block_bits + , size_t(0) + , testnet4_asert_anchor_block_bits + , scalenet_asert_anchor_block_bits + , chipnet_asert_anchor_block_bits + ); + + return {height, ancestor_time, bits}; +} +#endif // KTH_CURRENCY_BCH + +std::expected validate_header::build_chain_state_data( + size_t height, + domain::chain::header const& header, + hash_digest const& hash, + header_index::index_t parent_idx, + header_index const& index) const { + + if (height == 0) { + spdlog::warn("[validate_header] build_chain_state_data: height 0 is not valid"); + return std::unexpected(error::operation_failed); + } + + // Get the map that defines what data we need to collect + auto const map = chain_state::get_map(height, checkpoints_, configured_forks_, network_); + + // Collect historical data from header_index (single traversal) + auto result = collect_historical_data(map, parent_idx, index); + if (!result) { + return std::unexpected(result.error()); + } + + auto& data = *result; + + // Set metadata + data.height = height; + data.hash = hash; + + // Set self values from the header being validated + data.bits.self = header.bits(); + data.version.self = header.version(); + data.timestamp.self = header.timestamp(); + + // Handle collision hash (for duplicate tx hash detection) + if (map.allow_collisions_height != chain_state::map::unrequested) { + auto const collision_idx = index.get_ancestor(parent_idx, static_cast(map.allow_collisions_height)); + data.allow_collisions_hash = (collision_idx != header_index::null_index) + ? index.get_hash(collision_idx) + : null_hash; + } else { + data.allow_collisions_hash = null_hash; + } + +#if ! defined(KTH_CURRENCY_BCH) + // BIP9 bit0/bit1 hashes + if (map.bip9_bit0_height != chain_state::map::unrequested) { + auto const bip9_idx = index.get_ancestor(parent_idx, static_cast(map.bip9_bit0_height)); + data.bip9_bit0_hash = (bip9_idx != header_index::null_index) + ? index.get_hash(bip9_idx) + : null_hash; + } else { + data.bip9_bit0_hash = null_hash; + } + + if (map.bip9_bit1_height != chain_state::map::unrequested) { + auto const bip9_idx = index.get_ancestor(parent_idx, static_cast(map.bip9_bit1_height)); + data.bip9_bit1_hash = (bip9_idx != header_index::null_index) + ? index.get_hash(bip9_idx) + : null_hash; + } else { + data.bip9_bit1_hash = null_hash; + } +#endif + +#if defined(KTH_CURRENCY_BCH) + // ABLA state - we don't have block size during header validation + // Initialize with default values; actual block size validation happens during block sync + data.abla_state = domain::chain::abla::state(settings_.abla_config, static_max_block_size(network_)); +#endif + + return data; +} + +code validate_header::accept_full(domain::chain::header const& header, + hash_digest const& hash, + size_t height, + header_index::index_t parent_idx, + header_index const& index) const { + // Basic chain continuity check + if (parent_idx != header_index::null_index) { + auto const expected_prev = index.get_prev_block_hash(parent_idx); + // parent_idx points to the parent header, so we need to check the parent's hash + auto const parent_hash = index.get_hash(parent_idx); + if (header.previous_block_hash() != parent_hash) { + return error::store_block_missing_parent; + } + } else if (height != 0) { + // Non-genesis block without parent + return error::store_block_missing_parent; + } + + // Build chain_state data from header_index + auto data_result = build_chain_state_data(height, header, hash, parent_idx, index); + if (!data_result) { + spdlog::error("[validate_header] accept_full: failed to build chain_state data for height {}", height); + return data_result.error(); + } + + // Create chain_state from the data +#if defined(KTH_CURRENCY_BCH) + auto const anchor = get_asert_anchor_block(); + chain_state state( + std::move(*data_result), + configured_forks_, + checkpoints_, + network_, + anchor, + settings_.asert_half_life, + settings_.abla_config, + leibniz_t(settings_.leibniz_activation_time), + cantor_t(settings_.cantor_activation_time) + ); +#else + chain_state state( + std::move(*data_result), + configured_forks_, + checkpoints_, + network_ + ); +#endif + + // Now perform the full header validation using chain_state + // This is equivalent to header_basis::accept() + + // 1. Difficulty check + if (header.bits() != state.work_required()) { + spdlog::debug("[validate_header] accept_full: incorrect PoW at height {}: " + "header bits={:#x}, required={:#x}", + height, header.bits(), state.work_required()); + return error::incorrect_proof_of_work; + } + + // 2. Checkpoint conflict check + if (state.is_checkpoint_conflict(hash)) { + return error::checkpoints_failed; + } + + // 3. Under checkpoint - skip remaining checks + if (state.is_under_checkpoint()) { + return error::success; + } + + // 4. Version check + if (header.version() < state.minimum_version()) { + spdlog::debug("[validate_header] accept_full: old version at height {}: " + "header version={}, minimum={}", + height, header.version(), state.minimum_version()); + return error::old_version_block; + } + + // 5. Median time past check + if (header.timestamp() <= state.median_time_past()) { + spdlog::debug("[validate_header] accept_full: timestamp too early at height {}: " + "header timestamp={}, MTP={}", + height, header.timestamp(), state.median_time_past()); + return error::timestamp_too_early; + } + + return error::success; +} + +// ============================================================================= +// Static validation functions (pure, no side effects) +// ============================================================================= + +code validate_header::accept_header( + domain::chain::header const& header, + hash_digest const& hash, + domain::chain::chain_state const& state) { + + // 1. Difficulty check + if (header.bits() != state.work_required()) { + return error::incorrect_proof_of_work; + } + + // 2. Checkpoint conflict check + if (state.is_checkpoint_conflict(hash)) { + return error::checkpoints_failed; + } + + // 3. Under checkpoint - skip remaining checks + if (state.is_under_checkpoint()) { + return error::success; + } + + // 4. Version check + if (header.version() < state.minimum_version()) { + return error::old_version_block; + } + + // 5. Median time past check + if (header.timestamp() <= state.median_time_past()) { + return error::timestamp_too_early; + } + + return error::success; +} + } // namespace kth::blockchain diff --git a/src/c-api/src/node.cpp b/src/c-api/src/node.cpp index 0d5dca0c..19bbf6be 100644 --- a/src/c-api/src/node.cpp +++ b/src/c-api/src/node.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -55,48 +54,42 @@ int kth_node_initchain(kth_node_t node) { #if ! defined(KTH_DB_READONLY) void kth_node_init_run_and_wait_for_signal(kth_node_t node, void* ctx, kth_start_modules_t mods, kth_run_handler_t handler) { - kth_node_cpp(node).init_run_and_wait_for_signal( - version(), - kth::start_modules_to_cpp(mods), - [node, ctx, handler](std::error_code const& ec) { - if (handler != nullptr) { - handler(node, ctx, kth::to_c_err(ec)); - } - }); + // Start node + auto ec = kth_node_cpp(node).start(); + if (handler != nullptr) { + handler(node, ctx, kth::to_c_err(ec)); + } + + if (ec == kth::error::success) { + // Wait for signal + kth_node_cpp(node).wait_for_stop_signal(); + // Stop node + kth_node_cpp(node).stop(); + } } void kth_node_init_run(kth_node_t node, void* ctx, kth_start_modules_t mods, kth_run_handler_t handler) { - kth_node_cpp(node).init_run(version(), kth::start_modules_to_cpp(mods), - [node, ctx, handler](std::error_code const& ec) { - if (handler != nullptr) { - handler(node, ctx, kth::to_c_err(ec)); - } + kth_node_cpp(node).start_async([node, ctx, handler](kth::code ec) { + if (handler != nullptr) { + handler(node, ctx, kth::to_c_err(ec)); + } }); } kth_error_code_t kth_node_init_run_sync(kth_node_t node, kth_start_modules_t mods) { - std::latch latch(1); //Note: workaround to fix an error on some versions of Boost.Threads - kth_error_code_t res; - - kth_node_cpp(node).init_run(version(), kth::start_modules_to_cpp(mods), - [&](std::error_code const& ec) { - res = kth::to_c_err(ec); - latch.count_down(); - } - ); - - latch.wait(); - return res; + auto ec = kth_node_cpp(node).start(); + return kth::to_c_err(ec); } #endif // ! defined(KTH_DB_READONLY) void kth_node_signal_stop(kth_node_t node) { - kth_node_cpp(node).signal_stop(); + kth_node_cpp(node).stop_async(); } int kth_node_close(kth_node_t node) { - return kth_node_cpp(node).close(); + kth_node_cpp(node).stop(); + return 1; // Success } int kth_node_stopped(kth_node_t node) { diff --git a/src/consensus/src/bch-rules/coins.h b/src/consensus/src/bch-rules/coins.h index 680c63da..71514e09 100644 --- a/src/consensus/src/bch-rules/coins.h +++ b/src/consensus/src/bch-rules/coins.h @@ -109,7 +109,7 @@ struct hash { } }; } -// return static_cast(SipHashUint256Extra(k0(), k1(), o.GetTxId(), o.GetN())); +// return size_t(SipHashUint256Extra(k0(), k1(), o.GetTxId(), o.GetN())); /** Cursor for iterating over CoinsView state */ class CCoinsViewCursor { diff --git a/src/consensus/src/bch-rules/script/interpreter.cpp b/src/consensus/src/bch-rules/script/interpreter.cpp index 721f8335..a5e128af 100644 --- a/src/consensus/src/bch-rules/script/interpreter.cpp +++ b/src/consensus/src/bch-rules/script/interpreter.cpp @@ -59,7 +59,7 @@ int FindAndDelete(CScript &script, const CScript &b) { opcodetype opcode; do { result.insert(result.end(), pc2, pc); - while (static_cast(end - pc) >= b.size() && + while (size_t(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; diff --git a/src/consensus/src/bch-rules/util/strencodings.h b/src/consensus/src/bch-rules/util/strencodings.h index 17356dd8..1fe1853c 100644 --- a/src/consensus/src/bch-rules/util/strencodings.h +++ b/src/consensus/src/bch-rules/util/strencodings.h @@ -252,7 +252,7 @@ bool ConvertBits(const O &outfn, I it, I end) { constexpr size_t maxv = (size_t{1} << tobits) - 1u; constexpr size_t max_acc = (size_t{1} << (frombits + tobits - 1u)) - 1u; while (it != end) { - acc = ((acc << frombits) | static_cast(*it)) & max_acc; + acc = ((acc << frombits) | size_t(*it)) & max_acc; bits += frombits; while (bits >= tobits) { bits -= tobits; diff --git a/src/consensus/src/btc-rules/script/interpreter.cpp b/src/consensus/src/btc-rules/script/interpreter.cpp index e636de5a..ea566062 100644 --- a/src/consensus/src/btc-rules/script/interpreter.cpp +++ b/src/consensus/src/btc-rules/script/interpreter.cpp @@ -260,7 +260,7 @@ int FindAndDelete(CScript& script, const CScript& b) do { result.insert(result.end(), pc2, pc); - while (static_cast(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) + while (size_t(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; diff --git a/src/database/include/kth/database/databases/internal_database.ipp b/src/database/include/kth/database/databases/internal_database.ipp index f9168491..4ff6bd0d 100644 --- a/src/database/include/kth/database/databases/internal_database.ipp +++ b/src/database/include/kth/database/databases/internal_database.ipp @@ -1103,9 +1103,16 @@ template result_code internal_database_basis::push_block(domain::chain::block const& block, uint32_t height, uint32_t median_time_past, bool insert_reorg, KTH_DB_txn* db_txn) { //precondition: block.transactions().size() >= 1 - auto res = push_block_header(block, height, db_txn); - if (res != result_code::success) { - return res; + result_code res = result_code::success; + + // With headers-first sync, header usually already exists. + // Only write header if it doesn't exist (for backward compatibility/edge cases). + auto existing_header = get_header(height, db_txn); + if ( ! existing_header.has_value()) { + res = push_block_header(block, height, db_txn); + if (res != result_code::success) { + return res; + } } auto const& txs = block.transactions(); diff --git a/src/domain/include/kth/domain/chain/block.hpp b/src/domain/include/kth/domain/chain/block.hpp index 23955c39..b16de53c 100644 --- a/src/domain/include/kth/domain/chain/block.hpp +++ b/src/domain/include/kth/domain/chain/block.hpp @@ -144,9 +144,10 @@ struct KD_API block : block_basis { size_t total_inputs(bool with_coinbase = true) const; code check() const; - code accept(bool transactions = true) const; - code accept(chain_state const& state, bool transactions = true) const; - code connect() const; + + /// Check block body only (skip header validation for headers-first sync). + /// Use this when headers have already been validated during header sync. + code check_body() const; // THIS IS FOR LIBRARY USE ONLY, DO NOT CREATE A DEPENDENCY ON IT. mutable validation_t validation{}; diff --git a/src/domain/include/kth/domain/chain/block_basis.hpp b/src/domain/include/kth/domain/chain/block_basis.hpp index 24cf1b5c..eb0ed01a 100644 --- a/src/domain/include/kth/domain/chain/block_basis.hpp +++ b/src/domain/include/kth/domain/chain/block_basis.hpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -159,20 +158,13 @@ struct KD_API block_basis { [[nodiscard]] code check(size_t serialized_size_false) const; + /// Check block body only (skip header validation for headers-first sync). + /// Use this when headers have already been validated during header sync. [[nodiscard]] - code check_transactions() const; - - [[nodiscard]] - code accept(chain_state const& state, size_t serialized_size, bool transactions = true) const; - - [[nodiscard]] - code accept_transactions(chain_state const& state) const; - - [[nodiscard]] - code connect(chain_state const& state) const; + code check_body(size_t serialized_size_false) const; [[nodiscard]] - code connect_transactions(chain_state const& state) const; + code check_transactions() const; // protected: void reset(); diff --git a/src/domain/include/kth/domain/chain/header.hpp b/src/domain/include/kth/domain/chain/header.hpp index a38256aa..b4e4eebd 100644 --- a/src/domain/include/kth/domain/chain/header.hpp +++ b/src/domain/include/kth/domain/chain/header.hpp @@ -106,8 +106,6 @@ struct KD_API header : header_basis, hash_memoizer
{ bool is_valid_proof_of_work(bool retarget = true) const; code check(bool retarget = false) const; - code accept(chain_state const& state) const; - // THIS IS FOR LIBRARY USE ONLY, DO NOT CREATE A DEPENDENCY ON IT. mutable validation_t validation{}; diff --git a/src/domain/include/kth/domain/chain/header_basis.hpp b/src/domain/include/kth/domain/chain/header_basis.hpp index 2a8fef51..e3d19cc1 100644 --- a/src/domain/include/kth/domain/chain/header_basis.hpp +++ b/src/domain/include/kth/domain/chain/header_basis.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -149,9 +148,6 @@ struct KD_API header_basis { [[nodiscard]] code check(hash_digest const& hash, bool retarget = false) const; - [[nodiscard]] - code accept(::kth::domain::chain::chain_state const& state, hash_digest const& hash) const; - void reset(); private: diff --git a/src/domain/include/kth/domain/config/parser.hpp b/src/domain/include/kth/domain/config/parser.hpp index ed40c425..8329d5cc 100644 --- a/src/domain/include/kth/domain/config/parser.hpp +++ b/src/domain/include/kth/domain/config/parser.hpp @@ -215,7 +215,7 @@ kth::infrastructure::config::checkpoint::list default_checkpoints(config::networ checkpoints.emplace_back("0000000017d92f88ed2c81885c57f999184860a042250510be06b3edd12e0dc5", 232000); } else if (network == domain::config::network::mainnet) { - checkpoints.reserve(60); + checkpoints.reserve(64); checkpoints.emplace_back("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 0); checkpoints.emplace_back("0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d", 11'111); checkpoints.emplace_back("000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6", 33'333); @@ -340,6 +340,11 @@ kth::infrastructure::config::checkpoint::list default_checkpoints(config::networ checkpoints.emplace_back("00000000000000000157a0a3dcdc80f1acd809648d238c1e893b26247091b3b4", 898'374); checkpoints.emplace_back("0000000000000000007e2e7dd49323c90d16fd76a521804d709f0d5a442fd42a", 898'375); + checkpoints.emplace_back("000000000000000000ff9445c5039fd67d02e901b3cefe8bd55c1d6afb5fe1cf", 900'000); + checkpoints.emplace_back("000000000000000000a2f9b4d4d79f527a664a9932bb1e3f6016ff66a438c302", 910'000); + checkpoints.emplace_back("0000000000000000016a9d52a9c0a7d7fd3cf1a7cea538565674613a65341186", 920'000); + checkpoints.emplace_back("000000000000000000ee3232281f632df96f4222361d564af0fc2e3da352e34f", 930'000); + // //2026-May Upgrade - leibniz - (1778846400) // checkpoints.emplace_back("", 0); // checkpoints.emplace_back("", 0); diff --git a/src/domain/include/kth/domain/constants/common.hpp b/src/domain/include/kth/domain/constants/common.hpp index 53adc4e4..ebc95755 100644 --- a/src/domain/include/kth/domain/constants/common.hpp +++ b/src/domain/include/kth/domain/constants/common.hpp @@ -8,14 +8,7 @@ #include #include -// #include -// #include - -// #include -// #include -// #include -// #include -// #include +#include namespace kth { diff --git a/src/domain/src/chain/block.cpp b/src/domain/src/chain/block.cpp index 7dfcd6a5..64513eed 100644 --- a/src/domain/src/chain/block.cpp +++ b/src/domain/src/chain/block.cpp @@ -429,20 +429,10 @@ code block::check() const { return block_basis::check(serialized_size()); } -code block::accept(bool transactions) const { - auto const state = validation.state; - return state ? accept(*state, transactions) : error::operation_failed; -} - -// These checks assume that prevout caching is completed on all tx.inputs. -code block::accept(chain_state const& state, bool transactions) const { - validation.start_accept = asio::steady_clock::now(); - return block_basis::accept(state, serialized_size(), transactions); -} - -code block::connect() const { - auto const state = validation.state; - return state ? block_basis::connect(*state) : error::operation_failed; +// Check block body only (skip header validation for headers-first sync). +code block::check_body() const { + validation.start_check = asio::steady_clock::now(); + return block_basis::check_body(serialized_size()); } } // namespace kth::domain::chain diff --git a/src/domain/src/chain/block_basis.cpp b/src/domain/src/chain/block_basis.cpp index d7459421..cfbe0ade 100644 --- a/src/domain/src/chain/block_basis.cpp +++ b/src/domain/src/chain/block_basis.cpp @@ -18,14 +18,12 @@ #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -44,7 +42,6 @@ namespace kth::domain::chain { -using namespace kth::domain::machine; using namespace boost::adaptors; // Constructors. @@ -441,26 +438,6 @@ code block_basis::check_transactions() const { return error::success; } -code block_basis::accept_transactions(chain_state const& state) const { - code ec; - for (auto const& tx : transactions_) { - if ( ! tx.validation.validated && (ec = tx.accept(state, false))) { - return ec; - } - } - return error::success; -} - -code block_basis::connect_transactions(chain_state const& state) const { - code ec; - for (auto const& tx : transactions_) { - if ( ! tx.validation.validated && (ec = tx.connect(state))) { - return ec; - } - } - return error::success; -} - // Validation. //----------------------------------------------------------------------------- @@ -470,10 +447,14 @@ code block_basis::check(size_t serialized_size_false) const { if ((ec = header_.check())) { return ec; - - // TODO(legacy): relates to total of tx.size(false) (pool cache). -> no witness size } + return check_body(serialized_size_false); +} + +// Check block body only (skip header validation for headers-first sync). +// Use this when headers have already been validated during header sync. +code block_basis::check_body(size_t serialized_size_false) const { if (serialized_size_false > static_absolute_max_block_size()) { return error::block_size_limit; } @@ -488,132 +469,27 @@ code block_basis::check(size_t serialized_size_false) const { if (is_extra_coinbases()) { return error::extra_coinbases; - // TODO(legacy): determinable from tx pool graph. } #if ! defined(KTH_CURRENCY_BCH) // BTC and LTC - //Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) - // and for BitcoinCash (BCH) before 2018-Nov-15. + // Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) + // and for BitcoinCash (BCH) before 2018-Nov-15. if (is_forward_reference()) { return error::forward_reference; } #endif - - // This is subset of is_internal_double_spend if collisions cannot happen. - ////else if ( ! is_distinct_transaction_set()) - //// return error::internal_duplicate; - - // TODO(legacy): determinable from tx pool graph. if (is_internal_double_spend()) { return error::block_internal_double_spend; - // TODO(legacy): relates height to tx.hash(false) (pool cache). } if ( ! is_valid_merkle_root()) { return error::merkle_mismatch; - - // We cannot know if bip16 is enabled at this point so we disable it. - // This will not make a difference unless prevouts are populated, in which - // case they are ignored. This means that p2sh sigops are not counted here. - // This is a preliminary check, the final count must come from connect(). - // Reenable once sigop caching is implemented, otherwise is deoptimization. - ////else if (signature_operations(false, false) > get_max_block_sigops()) - //// return error::block_legacy_sigop_limit; } return check_transactions(); } -// These checks assume that prevout caching is completed on all tx.inputs. - - -code block_basis::accept(chain_state const& state, size_t serialized_size, bool transactions) const { - auto const bip16 = state.is_enabled(rule_fork::bip16_rule); - auto const bip34 = state.is_enabled(rule_fork::bip34_rule); - auto const bip113 = state.is_enabled(rule_fork::bip113_rule); - auto const bip141 = false; // No segwit - - code ec; - if ((ec = header_.accept(state))) { - return ec; - } - - if (state.is_lobachevski_enabled()) { - if (serialized_size > state.dynamic_max_block_size()) { - return error::block_size_limit; - } - } else if (state.is_pythagoras_enabled()) { - if (serialized_size > static_max_block_size(state.network())) { - return error::block_size_limit; - } - } else { - if (serialized_size > max_block_size::mainnet_old) { - return error::block_size_limit; - } - } - - if (state.is_under_checkpoint()) { - return error::success; - } - - - //Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) - // and for BitcoinCash (BCH) before 2018-Nov-15. - - if (state.is_euclid_enabled()) { - if ( ! is_canonical_ordered()) { - return error::non_canonical_ordered; - } - } else { - if (is_forward_reference()) { - return error::forward_reference; - } - } - - if (bip34 && !is_valid_coinbase_script(state.height())) { - return error::coinbase_height_mismatch; - } - - // TODO(legacy): relates height to total of tx.fee (pool cach). - if ( ! is_valid_coinbase_claim(state.height())) { - return error::coinbase_value_limit; - } - - // TODO(legacy): relates median time past to tx.locktime (pool cache min tx.time). - auto const block_time = bip113 ? state.median_time_past() : header_.timestamp(); - if ( ! is_final(state.height(), block_time)) { - return error::block_non_final; - } - -#if defined(KTH_CURRENCY_BCH) - if ( ! state.is_fermat_enabled()) { -#endif - // TODO(legacy): determine if performance benefit is worth excluding sigops here. - // TODO(legacy): relates block limit to total of tx.sigops (pool cache tx.sigops). - // This recomputes sigops to include p2sh from prevouts. - size_t const allowed_sigops = get_allowed_sigops(serialized_size); - if (transactions && (signature_operations(bip16, bip141) > allowed_sigops)) { - return error::block_embedded_sigop_limit; - } -#if defined(KTH_CURRENCY_BCH) - } -#endif - - if (transactions) { - return accept_transactions(state); - } - - return ec; -} - -code block_basis::connect(chain_state const& state) const { - if (state.is_under_checkpoint()) { - return error::success; - } - return connect_transactions(state); -} - // Non-member functions. //----------------------------------------------------------------------------- diff --git a/src/domain/src/chain/header.cpp b/src/domain/src/chain/header.cpp index 753505d8..c34573bb 100644 --- a/src/domain/src/chain/header.cpp +++ b/src/domain/src/chain/header.cpp @@ -148,8 +148,4 @@ code header::check(bool retarget) const { return header_basis::check(hash_pow(), retarget); } -code header::accept(chain_state const& state) const { - return header_basis::accept(state, hash_pow()); -} - } // namespace kth::domain::chain diff --git a/src/domain/src/chain/header_basis.cpp b/src/domain/src/chain/header_basis.cpp index fa3dc672..a2d48151 100644 --- a/src/domain/src/chain/header_basis.cpp +++ b/src/domain/src/chain/header_basis.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -268,28 +267,4 @@ code header_basis::check(hash_digest const& hash, bool retarget) const { return error::success; } -code header_basis::accept(chain_state const& state, hash_digest const& hash) const { - if (bits_ != state.work_required()) { - return error::incorrect_proof_of_work; - } - - if (state.is_checkpoint_conflict(hash)) { - return error::checkpoints_failed; - } - - if (state.is_under_checkpoint()) { - return error::success; - } - - if (version_ < state.minimum_version()) { - return error::old_version_block; - } - - if (timestamp_ <= state.median_time_past()) { - return error::timestamp_too_early; - } - - return error::success; -} - } // namespace kth::domain::chain diff --git a/src/infrastructure/include/kth/infrastructure.hpp b/src/infrastructure/include/kth/infrastructure.hpp index 17ffb776..389564ef 100644 --- a/src/infrastructure/include/kth/infrastructure.hpp +++ b/src/infrastructure/include/kth/infrastructure.hpp @@ -112,6 +112,8 @@ #include #include #include +#include +#include #include #include diff --git a/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp b/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp new file mode 100644 index 00000000..5da36b06 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp @@ -0,0 +1,157 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP +#define KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP + +#include +#include +#include +#include + +#include + +namespace kth { + +// ============================================================================= +// CPU Executor (Dedicated Thread Pool for CPU-Bound Work) +// ============================================================================= +// +// A specialized executor for CPU-bound operations that should not block the +// IO thread pool. This separates IO-bound async operations from CPU-intensive +// work like block validation, transaction verification, and cryptographic ops. +// +// Key properties: +// - Separate thread pool from IO operations +// - Sized to match hardware concurrency by default +// - Async interface via awaitable for seamless coroutine integration +// - Work can be posted from any thread +// +// Usage in coroutines: +// cpu_executor cpu; +// +// awaitable validate_block(block_ptr block) { +// // Offload CPU-intensive validation to CPU pool +// bool valid = co_await cpu.execute([&block]() { +// return block->is_valid(); // Runs on CPU pool thread +// }); +// +// if (!valid) { +// throw validation_error("Invalid block"); +// } +// } +// +// Architecture: +// ┌─────────────────┐ ┌─────────────────┐ +// │ IO Thread Pool │ │ CPU Thread Pool │ +// │ (network I/O) │ │ (validation) │ +// │ │ │ │ +// │ peer1.run() │ │ validate() │ +// │ peer2.run() │ ───► │ verify_sig() │ +// │ accept_loop() │ │ hash_block() │ +// │ ... │ │ ... │ +// └─────────────────┘ └─────────────────┘ +// +// ============================================================================= + +class cpu_executor { +public: + // Construct with specified number of threads + // Default: hardware_concurrency (number of CPU cores) + explicit cpu_executor(size_t threads = std::thread::hardware_concurrency()) + : pool_(threads > 0 ? threads : 1) + {} + + // Non-copyable, non-movable + cpu_executor(cpu_executor const&) = delete; + cpu_executor& operator=(cpu_executor const&) = delete; + cpu_executor(cpu_executor&&) = delete; + cpu_executor& operator=(cpu_executor&&) = delete; + + ~cpu_executor() { + stop(); + join(); + } + + // Execute a callable on the CPU pool and return result via awaitable. + // This is the primary interface for offloading CPU work from coroutines. + // + // Example: + // auto result = co_await cpu.execute([]() { + // return expensive_computation(); + // }); + // + template + auto execute(F&& work) -> ::asio::awaitable> { + using result_type = std::invoke_result_t; + + co_return co_await ::asio::co_spawn( + pool_.get_executor(), + [w = std::forward(work)]() -> ::asio::awaitable { + if constexpr (std::is_void_v) { + std::invoke(std::move(w)); + co_return; + } else { + co_return std::invoke(std::move(w)); + } + }, + ::asio::use_awaitable + ); + } + + // Post work to the CPU pool without waiting for result. + // Use when you don't need the result in the calling coroutine. + template + void post(F&& work) { + ::asio::post(pool_.get_executor(), std::forward(work)); + } + + // Get the underlying executor for advanced use cases + [[nodiscard]] + auto get_executor() { + return pool_.get_executor(); + } + + // Stop accepting new work + void stop() { + pool_.stop(); + } + + // Wait for all work to complete + void join() { + pool_.join(); + } + + // Get number of threads in the pool + [[nodiscard]] + size_t thread_count() const noexcept { + return thread_count_; + } + +private: + ::asio::thread_pool pool_; + size_t thread_count_{std::thread::hardware_concurrency()}; +}; + +// ============================================================================= +// Global CPU Executor Access +// ============================================================================= +// +// For convenience, a global CPU executor can be used. However, prefer passing +// the executor explicitly for better testability and control. +// +// Usage: +// auto& cpu = kth::global_cpu_executor(); +// co_await cpu.execute([]() { ... }); +// +// ============================================================================= + +inline cpu_executor& global_cpu_executor() { + static cpu_executor instance; + return instance; +} + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp new file mode 100644 index 00000000..1ad32279 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp @@ -0,0 +1,230 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_TASK_GROUP_HPP +#define KTH_INFRASTRUCTURE_TASK_GROUP_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace kth { + +// ============================================================================= +// Task Group (Nursery Pattern for Structured Concurrency) +// ============================================================================= +// +// A task_group manages a set of concurrent coroutines and ensures all complete +// before the group is destroyed. This implements the "nursery" pattern from +// structured concurrency (similar to Trio in Python or Kotlin coroutines). +// +// Key properties: +// - All spawned tasks are tracked automatically +// - join() waits for ALL tasks to complete +// - No tasks are "lost" or detached +// - Exception in any task can be propagated (future enhancement) +// +// Usage: +// task_group tasks(executor); +// +// tasks.spawn([&]() -> awaitable { +// co_await do_work_1(); +// }); +// +// tasks.spawn([&]() -> awaitable { +// co_await do_work_2(); +// }); +// +// co_await tasks.join(); // Waits for both tasks +// +// Integration with structured concurrency: +// awaitable parent_task() { +// task_group children(co_await this_coro::executor); +// +// children.spawn(child_1()); +// children.spawn(child_2()); +// +// co_await children.join(); // Parent waits for all children +// } +// +// ============================================================================= + +class task_group { +public: + explicit task_group(::asio::any_io_executor executor) + : executor_(std::move(executor)) + , done_channel_(executor_, 1) + {} + + // Non-copyable, non-movable (prevents accidental misuse) + task_group(task_group const&) = delete; + task_group& operator=(task_group const&) = delete; + task_group(task_group&&) = delete; + task_group& operator=(task_group&&) = delete; + + ~task_group() { + // In debug builds, assert that join() was called + // In release, just log a warning if tasks are still active + if (active_count_.load() > 0) { + // Tasks still running - this is a programming error + // The destructor should only be called after join() + } + } + + // Spawn a coroutine into the group. + // The coroutine will be tracked and join() will wait for it. + // Note: This uses ONE internal detached spawn, but the task is tracked. + // + // Accepts either: + // - An awaitable directly: tasks.spawn(some_coro()) + // - A callable returning awaitable: tasks.spawn([&]() -> awaitable { ... }) + template + void spawn(Coro&& coro) { + ++active_count_; + ++total_spawned_; + + ::asio::co_spawn(executor_, + [this, c = std::forward(coro)]() mutable -> ::asio::awaitable { + try { + if constexpr (std::is_invocable_v) { + // It's a callable (lambda, function) - invoke it to get the awaitable + co_await std::invoke(std::move(c)); + } else { + // It's already an awaitable - just await it directly + co_await std::move(c); + } + } catch (...) { + // TODO: Store exception for later propagation + // For now, just decrement and signal + } + decrement_and_signal(); + }, + ::asio::detached); // Single controlled detached point + } + + // Wait for all spawned tasks to complete. + // This MUST be called before the task_group is destroyed. + [[nodiscard]] + ::asio::awaitable join() { + if (active_count_.load() == 0) { + co_return; + } + + // Wait for signal that all tasks completed + auto [ec] = co_await done_channel_.async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + // Channel closed or received signal - all tasks done + co_return; + } + + // Check if there are active tasks + [[nodiscard]] + bool has_active_tasks() const noexcept { + return active_count_.load() > 0; + } + + // Get number of currently active tasks + [[nodiscard]] + size_t active_count() const noexcept { + return active_count_.load(); + } + + // Get total number of tasks spawned (including completed) + [[nodiscard]] + size_t total_spawned() const noexcept { + return total_spawned_.load(); + } + +private: + void decrement_and_signal() { + auto const prev = active_count_.fetch_sub(1); + if (prev == 1) { + // We were the last task - signal completion + // Use try_send to avoid blocking if no one is waiting yet + done_channel_.try_send(std::error_code{}); + } + } + + ::asio::any_io_executor executor_; + std::atomic active_count_{0}; + std::atomic total_spawned_{0}; + + // Channel to signal when all tasks complete + // Capacity of 1 is sufficient - we only send once when count hits 0 + concurrent_event_channel done_channel_; +}; + +// ============================================================================= +// Scoped Task Group (RAII wrapper) +// ============================================================================= +// +// Automatically joins on scope exit. Useful for ensuring structured concurrency +// even when exceptions occur. +// +// Usage: +// { +// scoped_task_group tasks(executor); +// tasks.spawn(work_1()); +// tasks.spawn(work_2()); +// } // Automatically waits here (blocking!) +// +// WARNING: The destructor blocks! Use with care. +// Prefer explicit co_await join() in coroutines. +// +// ============================================================================= + +class scoped_task_group { +public: + explicit scoped_task_group(::asio::any_io_executor executor) + : executor_(executor) + , group_(std::move(executor)) + {} + + ~scoped_task_group() { + if (group_.has_active_tasks()) { + // Block until all tasks complete + // This is a blocking call - use sparingly! + std::promise done; + auto future = done.get_future(); + + ::asio::co_spawn(executor_, + [this, &done]() -> ::asio::awaitable { + co_await group_.join(); + done.set_value(); + }, + ::asio::detached); + + future.wait(); + } + } + + template + void spawn(Coro&& coro) { + group_.spawn(std::forward(coro)); + } + + [[nodiscard]] + ::asio::awaitable join() { + return group_.join(); + } + + [[nodiscard]] size_t active_count() const noexcept { + return group_.active_count(); + } + +private: + ::asio::any_io_executor executor_; + task_group group_; +}; + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_TASK_GROUP_HPP diff --git a/src/infrastructure/src/log/sink.cpp b/src/infrastructure/src/log/sink.cpp index 8022fc36..14892309 100644 --- a/src/infrastructure/src/log/sink.cpp +++ b/src/infrastructure/src/log/sink.cpp @@ -11,24 +11,25 @@ namespace kth::log { -void initialize(std::string const& debug_file, std::string const& error_file, bool stdout_enabled, bool verbose) { +void initialize(std::string const& debug_file, [[maybe_unused]] std::string const& error_file, bool stdout_enabled, bool verbose) { try { auto debug_file_sink = std::make_shared(debug_file, true); + // Debug file captures debug+ normally, or trace+ when verbose debug_file_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); - auto error_file_sink = std::make_shared(error_file, true); - error_file_sink->set_level(spdlog::level::err); - if (stdout_enabled) { auto stdout_sink = std::make_shared(); stdout_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::info); - auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink, stdout_sink})); - logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, stdout_sink})); + // Logger level must be trace so all messages reach the debug file sink. + // Each sink filters independently based on its own level. + logger->set_level(spdlog::level::trace); logger->flush_on(spdlog::level::info); spdlog::set_default_logger(logger); } else { - auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink})); - logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink})); + // Logger level must be trace so all messages reach the debug file sink. + logger->set_level(spdlog::level::trace); logger->flush_on(spdlog::level::debug); spdlog::set_default_logger(logger); } diff --git a/src/infrastructure/src/utility/system_memory.cpp b/src/infrastructure/src/utility/system_memory.cpp index 99ed3e31..5d9f64fb 100644 --- a/src/infrastructure/src/utility/system_memory.cpp +++ b/src/infrastructure/src/utility/system_memory.cpp @@ -34,7 +34,7 @@ size_t get_total_system_memory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { - return static_cast(status.ullTotalPhys); + return size_t(status.ullTotalPhys); } return 0; #elif defined(__APPLE__) @@ -42,14 +42,14 @@ size_t get_total_system_memory() { uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctl(mib, 2, &memsize, &len, nullptr, 0) == 0) { - return static_cast(memsize); + return size_t(memsize); } return 0; #elif defined(__FreeBSD__) uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctlbyname("hw.physmem", &memsize, &len, nullptr, 0) == 0) { - return static_cast(memsize); + return size_t(memsize); } return 0; #elif defined(__linux__) @@ -68,7 +68,7 @@ size_t get_available_system_memory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { - return static_cast(status.ullAvailPhys); + return size_t(status.ullAvailPhys); } return 0; #elif defined(__APPLE__) @@ -84,7 +84,7 @@ size_t get_available_system_memory() { // Available = free + inactive + purgeable (can be reclaimed) uint64_t available = (uint64_t)(vm_stats.free_count + vm_stats.inactive_count + vm_stats.purgeable_count) * page_size; - return static_cast(available); + return size_t(available); } return 0; #elif defined(__FreeBSD__) @@ -97,7 +97,7 @@ size_t get_available_system_memory() { unsigned int inactive_count = 0; len = sizeof(inactive_count); sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_count, &len, nullptr, 0); - return static_cast((free_count + inactive_count)) * page_size; + return size_t((free_count + inactive_count)) * page_size; } return 0; #elif defined(__linux__) @@ -109,7 +109,7 @@ size_t get_available_system_memory() { unsigned long long mem_kb; if (sscanf(line, "MemAvailable: %llu kB", &mem_kb) == 1) { fclose(f); - return static_cast(mem_kb * 1024); + return size_t(mem_kb * 1024); } } fclose(f); @@ -143,7 +143,7 @@ size_t get_resident_memory() { #elif defined(_WIN32) PROCESS_MEMORY_COUNTERS pmc; if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { - return static_cast(pmc.WorkingSetSize); + return size_t(pmc.WorkingSetSize); } return 0; #elif defined(__APPLE__) @@ -157,7 +157,7 @@ size_t get_resident_memory() { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage) == 0) { // ru_maxrss is in kilobytes on FreeBSD - return static_cast(usage.ru_maxrss) * 1024; + return size_t(usage.ru_maxrss) * 1024; } return 0; #elif defined(__linux__) diff --git a/src/network/include/kth/network/p2p_node.hpp b/src/network/include/kth/network/p2p_node.hpp index cd41dd22..5c2d132b 100644 --- a/src/network/include/kth/network/p2p_node.hpp +++ b/src/network/include/kth/network/p2p_node.hpp @@ -133,6 +133,31 @@ struct connection_result { handshake_result handshake; }; +// ============================================================================= +// Peer event (for peer_supervisor channel) +// ============================================================================= + +enum class peer_direction { + inbound, + outbound +}; + +/// Result of handshake sent back to connect() caller +struct handshake_response { + code result; // error::success or error code +}; + +/// Channel type for handshake response (one-shot) +using handshake_response_channel = concurrent_channel; + +struct peer_event { + peer_session::ptr peer; + peer_direction direction; + // Optional response channel for connect() to wait on handshake result + // If nullptr, no response is expected (e.g., for seeding connections) + std::shared_ptr response_channel; +}; + // ============================================================================= // P2P Node (main networking class) // ============================================================================= @@ -235,6 +260,9 @@ class KN_API p2p_node { ::asio::awaitable run_peer_protocols(peer_session::ptr peer); ::asio::awaitable maintain_outbound_connections(); + // Peer supervisor - manages all peer lifecycles (structured concurrency) + ::asio::awaitable peer_supervisor(); + // Helper for seeding - takes params by value to avoid lambda capture issues ::asio::awaitable connect_to_seed( std::string seed_host, @@ -253,10 +281,18 @@ class KN_API p2p_node { std::atomic stopped_{true}; std::atomic seeded_{false}; + std::atomic supervisor_ready_{false}; // Signals that peer_supervisor is ready kth::atomic top_block_; // Message dispatcher for routing messages to handlers message_dispatcher dispatcher_; + + // Channels for structured concurrency (peer_supervisor pattern) + // New peers are sent here by run_inbound/run_outbound, processed by peer_supervisor + std::unique_ptr> new_peer_channel_; + + // Signal to stop the peer_supervisor gracefully + std::unique_ptr stop_signal_; }; } // namespace kth::network diff --git a/src/network/include/kth/network/peer_session.hpp b/src/network/include/kth/network/peer_session.hpp index 74f54e07..29e004a8 100644 --- a/src/network/include/kth/network/peer_session.hpp +++ b/src/network/include/kth/network/peer_session.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include // Asio includes for coroutines @@ -71,7 +72,10 @@ class KN_API peer_session : public std::enable_shared_from_this { using inbound_channel = concurrent_channel; /// Construct a peer session from an established socket - peer_session(socket_type socket, settings const& settings); + /// @param socket The connected socket + /// @param settings Network settings + /// @param inbound True if this is an inbound connection (we accepted it) + peer_session(socket_type socket, settings const& settings, bool inbound = false); /// Destructor - ensures clean shutdown ~peer_session(); @@ -122,6 +126,39 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] inbound_channel& messages(); + // ------------------------------------------------------------------------- + // Direct I/O (for handshake before run() starts) + // ------------------------------------------------------------------------- + // These methods read/write directly to the socket without using channels. + // Use ONLY before calling run() - after run() starts, use send() and messages(). + + /// Read a message directly from the socket (bypasses inbound channel) + /// Use this for handshake before run() is started + [[nodiscard]] + awaitable_expected read_message_direct(); + + /// Send a message directly to the socket (bypasses outbound channel) + /// Use this for handshake before run() is started + template + ::asio::awaitable send_direct(Message const& message) { + if (stopped()) { + co_return error::channel_stopped; + } + + auto data = domain::message::serialize(version_.load(), message, protocol_magic_); + auto [ec, bytes_written] = co_await ::asio::async_write( + socket_, + ::asio::buffer(data), + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + co_return error::boost_to_error_code(ec); + } + + bytes_sent_.fetch_add(bytes_written, std::memory_order_relaxed); + co_return error::success; + } + // ------------------------------------------------------------------------- // Response channels (for request/response patterns like getheaders/headers) // ------------------------------------------------------------------------- @@ -152,6 +189,11 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] infrastructure::config::authority const& authority() const; + /// Get formatted string with authority and user agent (for logging) + /// Returns "[ip:port user_agent]" or "[ip:port]" if user agent not yet known + [[nodiscard]] + std::string authority_with_agent() const; + /// Get/set the negotiated protocol version [[nodiscard]] uint32_t negotiated_version() const; @@ -162,6 +204,10 @@ class KN_API peer_session : public std::enable_shared_from_this { domain::message::version::const_ptr peer_version() const; void set_peer_version(domain::message::version::const_ptr value); + /// Get short user agent (e.g., "BCHN:28.0.1") - computed once from peer_version + [[nodiscard]] + std::string const& short_user_agent() const; + /// Get/set the nonce for this connection [[nodiscard]] uint64_t nonce() const; @@ -172,6 +218,79 @@ class KN_API peer_session : public std::enable_shared_from_this { bool notify() const; void set_notify(bool value); + /// Check if this is an inbound connection (peer connected to us) + [[nodiscard]] + bool is_inbound() const; + + /// Check if this is an outbound connection (we connected to peer) + /// BCHN prefers outbound peers for sync (fPreferredDownload) + [[nodiscard]] + bool is_outbound() const; + + /// Check if peer is a full node (has NODE_NETWORK or NODE_NETWORK_LIMITED service) + /// BCHN: fClient = !(services & NODE_NETWORK) && !(services & NODE_NETWORK_LIMITED) + [[nodiscard]] + bool is_full_node() const; + + /// Check if peer is a light client (no NODE_NETWORK service) + [[nodiscard]] + bool is_client() const; + + /// Check if this is a one-shot connection (connect, get addrs, disconnect) + [[nodiscard]] + bool is_one_shot() const; + + /// Mark this as a one-shot connection + void set_one_shot(bool value); + + /// Check if peer has a specific permission + [[nodiscard]] + bool has_permission(permission_flags flag) const; + + /// Get all permission flags for this peer + [[nodiscard]] + permission_flags permissions() const; + + /// Set permission flags for this peer + void set_permissions(permission_flags flags); + + /// Add a permission flag + void add_permission(permission_flags flag); + + /// Remove a permission flag + void clear_permission(permission_flags flag); + + /// Check if this peer is preferred for download (BCHN fPreferredDownload) + /// fPreferredDownload = (!fInbound || HasPermission(PF_NOBAN)) && !fOneShot && !fClient + [[nodiscard]] + bool is_preferred_download() const; + + // ------------------------------------------------------------------------- + // Statistics (lock-free, benign data races acceptable) + // ------------------------------------------------------------------------- + + /// Get total bytes received from this peer + [[nodiscard]] + size_t bytes_received() const; + + /// Get total bytes sent to this peer + [[nodiscard]] + size_t bytes_sent() const; + + /// Get last ping latency in milliseconds + [[nodiscard]] + uint32_t ping_latency_ms() const; + + /// Record a ping sent (store nonce and time for latency calculation) + void record_ping_sent(uint64_t nonce); + + /// Record a pong received, returns true if nonce matches pending ping + bool record_pong_received(uint64_t nonce); + + /// Get connection time + [[nodiscard]] + std::chrono::steady_clock::time_point connection_time() const; + private: // ------------------------------------------------------------------------- // Internal coroutines @@ -234,6 +353,26 @@ class KN_API peer_session : public std::enable_shared_from_this { std::atomic nonce_{0}; std::atomic notify_{true}; kth::atomic peer_version_; + std::string short_user_agent_; // Computed once from peer_version_ for logging + + // Connection direction (set at construction, never changes) + bool const inbound_connection_; + + // Connection flags (can be set after construction) + std::atomic one_shot_{false}; + std::atomic permission_flags_{uint32_t(permission_flags::none)}; + + // Statistics (lock-free, benign data races acceptable) + std::atomic bytes_received_{0}; + std::atomic bytes_sent_{0}; + std::atomic ping_latency_ms_{0}; + std::chrono::steady_clock::time_point connection_time_{std::chrono::steady_clock::now()}; + + // Ping tracking (lock-free) + // We store time as nanoseconds since steady_clock epoch for atomic access + // Benign data races are acceptable for statistics + std::atomic pending_ping_nonce_{0}; + std::atomic pending_ping_time_ns_{0}; // Buffers (only accessed from read_loop, no synchronization needed) data_chunk heading_buffer_; diff --git a/src/network/include/kth/network/protocols_coro.hpp b/src/network/include/kth/network/protocols_coro.hpp index 98d80eb2..f3f7cbee 100644 --- a/src/network/include/kth/network/protocols_coro.hpp +++ b/src/network/include/kth/network/protocols_coro.hpp @@ -167,6 +167,23 @@ KN_API awaitable_expected perform_handshake( peer_session& peer, handshake_config const& config); +/// Perform version handshake using direct socket I/O (no message pump needed) +/// This version reads/writes directly to the socket, so peer->run() does NOT +/// need to be running. Use this to avoid detached coroutines in connect/accept. +/// +/// Usage: +/// auto peer = co_await async_connect(...); +/// auto result = co_await perform_handshake_direct(*peer, config); // No run() needed! +/// // After handshake, send peer to supervisor which starts run() +/// +/// @param peer The peer session (run() must NOT be running yet) +/// @param config Handshake configuration +/// @return handshake_result on success, error code on failure +[[nodiscard]] +KN_API awaitable_expected perform_handshake_direct( + peer_session& peer, + handshake_config const& config); + /// Create handshake config from network settings [[nodiscard]] KN_API handshake_config make_handshake_config( @@ -281,6 +298,26 @@ KN_API awaitable_expected request_block( hash_digest const& block_hash, std::chrono::seconds timeout); +/// Result of batch block request - block with its height +struct block_with_height { + uint32_t height; + domain::message::block block; +}; + +/// Request multiple blocks in a single getdata (batch mode) +/// Sends ONE getdata with all hashes and receives blocks as they arrive. +/// Much more efficient than requesting blocks one at a time. +/// @param peer The peer session +/// @param blocks Vector of {height, hash} pairs to request +/// @param timeout Maximum time to wait for ALL blocks +/// @return Vector of received blocks with heights, or error +/// @note Blocks may be received out of order; vector is sorted by height on return +[[nodiscard]] +KN_API awaitable_expected> request_blocks_batch( + peer_session& peer, + std::vector> const& blocks, + std::chrono::seconds timeout); + // ----------------------------------------------------------------------------- // Inventory Protocol // ----------------------------------------------------------------------------- diff --git a/src/network/include/kth/network/settings.hpp b/src/network/include/kth/network/settings.hpp index 938f492a..488d8fda 100644 --- a/src/network/include/kth/network/settings.hpp +++ b/src/network/include/kth/network/settings.hpp @@ -42,6 +42,7 @@ struct KN_API settings { uint32_t channel_germination_seconds; uint32_t host_pool_capacity; kth::path hosts_file; + kth::path banlist_file; infrastructure::config::authority self; infrastructure::config::authority::list blacklist; infrastructure::config::endpoint::list peers; diff --git a/src/network/src/banlist.cpp b/src/network/src/banlist.cpp new file mode 100644 index 00000000..a6bdc984 --- /dev/null +++ b/src/network/src/banlist.cpp @@ -0,0 +1,236 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include + +#include + +namespace kth::network { + +// ============================================================================= +// Construction +// ============================================================================= + +banlist::banlist(kth::path file_path) + : file_path_(std::move(file_path)) +{} + +// ============================================================================= +// Ban/Unban operations +// ============================================================================= + +void banlist::ban( + ::asio::ip::address const& ip, + std::chrono::seconds duration, + ban_reason reason) +{ + ban_entry entry; + entry.create_time = clock::now(); + entry.ban_until = entry.create_time + duration; + entry.reason = reason; + + bans_.insert_or_assign(ip, entry); + + // Log with human-readable duration + auto const duration_secs = duration.count(); + if (duration_secs >= 365 * 24 * 60 * 60) { + // More than a year = "permanent" + spdlog::info("[banlist] Banned {} permanently, reason: {}", + ip.to_string(), to_string(reason)); + } else if (duration_secs >= 24 * 60 * 60) { + spdlog::info("[banlist] Banned {} for {} days, reason: {}", + ip.to_string(), duration_secs / (24 * 60 * 60), to_string(reason)); + } else if (duration_secs >= 60 * 60) { + spdlog::info("[banlist] Banned {} for {} hours, reason: {}", + ip.to_string(), duration_secs / (60 * 60), to_string(reason)); + } else { + spdlog::info("[banlist] Banned {} for {}s, reason: {}", + ip.to_string(), duration_secs, to_string(reason)); + } + + // Persist to file immediately (bans are rare, so I/O overhead is acceptable) + save(); +} + +void banlist::ban( + infrastructure::config::authority const& authority, + std::chrono::seconds duration, + ban_reason reason) +{ + ban(authority.asio_ip(), duration, reason); +} + +bool banlist::unban(::asio::ip::address const& ip) { + auto const erased = bans_.erase(ip); + if (erased > 0) { + spdlog::info("[banlist] Unbanned {}", ip.to_string()); + save(); // Persist immediately + return true; + } + return false; +} + +bool banlist::unban(infrastructure::config::authority const& authority) { + return unban(authority.asio_ip()); +} + +// ============================================================================= +// Query operations +// ============================================================================= + +bool banlist::is_banned(::asio::ip::address const& ip) const { + bool banned = false; + bans_.cvisit(ip, [&banned](auto const& entry) { + banned = ! entry.second.is_expired(); + }); + return banned; +} + +bool banlist::is_banned(infrastructure::config::authority const& authority) const { + return is_banned(authority.asio_ip()); +} + +std::optional banlist::get_ban(::asio::ip::address const& ip) const { + std::optional result; + bans_.cvisit(ip, [&result](auto const& entry) { + if ( ! entry.second.is_expired()) { + result = entry.second; + } + }); + return result; +} + +size_t banlist::size() const { + return bans_.size(); +} + +void banlist::clear() { + bans_.clear(); + spdlog::info("[banlist] Cleared all bans"); + save(); // Persist immediately +} + +void banlist::sweep_expired() { + size_t removed = 0; + + bans_.erase_if([&removed](auto const& entry) { + if (entry.second.is_expired()) { + spdlog::debug("[banlist] Expired ban removed for {}", entry.first.to_string()); + ++removed; + return true; + } + return false; + }); + + if (removed > 0) { + spdlog::debug("[banlist] Swept {} expired bans", removed); + } +} + +std::vector> banlist::get_all_bans() const { + std::vector> result; + + bans_.cvisit_all([&result](auto const& entry) { + if ( ! entry.second.is_expired()) { + result.emplace_back(entry.first.to_string(), entry.second); + } + }); + + return result; +} + +// ============================================================================= +// Persistence +// ============================================================================= + +bool banlist::load() { + if (file_path_.empty()) { + return true; // No persistence configured + } + + std::ifstream file(file_path_); + if ( ! file.is_open()) { + // File doesn't exist yet - that's OK + return true; + } + + bans_.clear(); + + std::string line; + size_t loaded = 0; + + while (std::getline(file, line)) { + if (line.empty() || line[0] == '#') { + continue; // Skip empty lines and comments + } + + std::istringstream iss(line); + std::string ip_str; + int64_t create_time_epoch; + int64_t ban_until_epoch; + int reason_int; + + if (iss >> ip_str >> create_time_epoch >> ban_until_epoch >> reason_int) { + std::error_code ec; + auto const ip = ::asio::ip::make_address(ip_str, ec); + if (ec) { + spdlog::warn("[banlist] Invalid IP address in banlist file: {}", ip_str); + continue; + } + + ban_entry entry; + entry.create_time = clock::time_point(std::chrono::seconds(create_time_epoch)); + entry.ban_until = clock::time_point(std::chrono::seconds(ban_until_epoch)); + entry.reason = ban_reason(reason_int); + + // Only load non-expired bans + if ( ! entry.is_expired()) { + bans_.insert_or_assign(ip, entry); + ++loaded; + } + } + } + + spdlog::info("[banlist] Loaded {} bans from {}", loaded, file_path_.string()); + return true; +} + +bool banlist::save() const { + if (file_path_.empty()) { + return true; // No persistence configured + } + + std::ofstream file(file_path_); + if ( ! file.is_open()) { + spdlog::error("[banlist] Failed to open {} for writing", file_path_.string()); + return false; + } + + file << "# Knuth banlist - format: IP create_time ban_until reason\n"; + + size_t saved = 0; + bans_.cvisit_all([&file, &saved](auto const& entry) { + if ( ! entry.second.is_expired()) { + auto const create_epoch = std::chrono::duration_cast( + entry.second.create_time.time_since_epoch()).count(); + auto const until_epoch = std::chrono::duration_cast( + entry.second.ban_until.time_since_epoch()).count(); + + file << entry.first.to_string() << ' ' + << create_epoch << ' ' + << until_epoch << ' ' + << int(entry.second.reason) << '\n'; + ++saved; + } + }); + + spdlog::debug("[banlist] Saved {} bans to {}", saved, file_path_.string()); + return true; +} + +} // namespace kth::network diff --git a/src/network/src/handlers/pong.cpp b/src/network/src/handlers/pong.cpp index 577cc33b..68f377da 100644 --- a/src/network/src/handlers/pong.cpp +++ b/src/network/src/handlers/pong.cpp @@ -13,8 +13,14 @@ ::asio::awaitable handle( peer_session& peer, domain::message::pong const& msg) { - // Just acknowledge receipt - could verify nonce if we tracked sent pings - spdlog::trace("[pong] Received pong from [{}], nonce: {}", peer.authority(), msg.nonce()); + // Record pong to calculate latency + if (peer.record_pong_received(msg.nonce())) { + spdlog::trace("[pong] Received pong from [{}], nonce: {}, latency: {}ms", + peer.authority(), msg.nonce(), peer.ping_latency_ms()); + } else { + spdlog::trace("[pong] Received unexpected pong from [{}], nonce: {}", + peer.authority(), msg.nonce()); + } co_return message_result::handled; } diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp index fa99c15b..58fe3964 100644 --- a/src/network/src/p2p_node.cpp +++ b/src/network/src/p2p_node.cpp @@ -21,22 +21,27 @@ using namespace std::chrono_literals; p2p_node::p2p_node(settings const& settings) : settings_(settings) - , pool_(settings.threads > 0 ? settings.threads : 1) + , pool_(thread_ceiling(settings.threads)) // 0 means use all cores , manager_(pool_.get_executor()) , hosts_(settings) + , banlist_(settings.banlist_file) , top_block_({null_hash, 0}) + , new_peer_channel_(std::make_unique>(pool_.get_executor(), 100)) + , stop_signal_(std::make_unique(pool_.get_executor(), 1)) { - spdlog::debug("[p2p_node] p2p_node constructor - member init complete"); + spdlog::debug("[p2p_node] p2p_node constructor - thread pool size: {}", pool_.size()); // Register default message handlers using typed registration // The make_handler<> wrapper handles parsing automatically dispatcher_.register_handler(handlers::ping::handle); dispatcher_.register_handler(handlers::pong::handle); - spdlog::debug("[p2p_node] p2p_node constructor completed successfully"); } p2p_node::~p2p_node() { + spdlog::debug("[p2p_node] destructor starting"); stop(); + spdlog::debug("[p2p_node] destructor - stop() done, calling join()..."); join(); + spdlog::debug("[p2p_node] destructor done"); } ::asio::awaitable p2p_node::start() { @@ -46,8 +51,14 @@ ::asio::awaitable p2p_node::start() { stopped_ = false; + // Load banlist from file (persisted bans survive restarts) + if (!banlist_.load()) { + spdlog::warn("[p2p_node] Failed to load banlist from file"); + } + // hosts_ loads from file in constructor - spdlog::info("[p2p_node] Loaded {} host addresses", hosts_.count()); + spdlog::info("[p2p_node] Loaded {} host addresses, {} banned IPs", + hosts_.count(), banlist_.size()); // Seed if needed if (hosts_.count() < settings_.host_pool_capacity / 2) { @@ -59,25 +70,63 @@ ::asio::awaitable p2p_node::start() { } ::asio::awaitable p2p_node::run() { + spdlog::debug("[p2p_node] run() starting"); + if (stopped_) { + spdlog::debug("[p2p_node] run() - already stopped"); co_return error::service_stopped; } - // Start inbound acceptor - ::asio::co_spawn(pool_.get_executor(), run_inbound(), ::asio::detached); - - // Start outbound connection manager - ::asio::co_spawn(pool_.get_executor(), run_outbound(), ::asio::detached); + // Run all network tasks in parallel using task_group on pool_ executor. + // We use task_group instead of && operator because && runs all coroutines + // on the caller's executor (which may be single-threaded). task_group + // uses pool_.get_executor() which has multiple threads, allowing true + // parallelism and proper coroutine scheduling. + task_group network_tasks(pool_.get_executor()); + + spdlog::debug("[p2p_node] Spawning peer_supervisor..."); + network_tasks.spawn([this]() -> ::asio::awaitable { + spdlog::debug("[p2p_node] peer_supervisor coroutine starting"); + co_await peer_supervisor(); + spdlog::debug("[p2p_node] peer_supervisor coroutine finished"); + }); + + spdlog::debug("[p2p_node] Spawning run_inbound..."); + network_tasks.spawn([this]() -> ::asio::awaitable { + spdlog::debug("[p2p_node] run_inbound coroutine starting"); + co_await run_inbound(); + spdlog::debug("[p2p_node] run_inbound coroutine finished"); + }); + + spdlog::debug("[p2p_node] Spawning run_outbound..."); + network_tasks.spawn([this]() -> ::asio::awaitable { + spdlog::debug("[p2p_node] run_outbound coroutine starting"); + co_await run_outbound(); + spdlog::debug("[p2p_node] run_outbound coroutine finished"); + }); + + // Wait for supervisor to be ready before connecting manual peers + while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { + co_await ::asio::post(pool_.get_executor(), ::asio::use_awaitable); + } - // Connect to configured manual peers - for (auto const& peer : settings_.peers) { - auto result = co_await connect(peer.host(), peer.port()); - if (!result) { - spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", - peer.host(), peer.port(), result.error().message()); + // Connect to configured manual peers (supervisor is now ready) + if (!settings_.peers.empty()) { + spdlog::debug("[p2p_node] run() - connecting to {} manual peers", settings_.peers.size()); + for (auto const& peer : settings_.peers) { + auto result = co_await connect(peer.host(), peer.port()); + if (!result) { + spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", + peer.host(), peer.port(), result.error().message()); + } } } + spdlog::debug("[p2p_node] All tasks spawned, waiting on join..."); + // Wait for all tasks to complete (i.e., until stop() is called) + co_await network_tasks.join(); + spdlog::debug("[p2p_node] All tasks completed"); + co_return error::success; } @@ -87,20 +136,41 @@ void p2p_node::stop() { } stopped_ = true; + supervisor_ready_ = false; // Reset for potential restart + + // Close stop_signal_ channel - this wakes up ALL waiters (peer_supervisor, + // maintain_outbound_connections) because async_receive returns error when closed + if (stop_signal_) { + stop_signal_->close(); + } - // Stop acceptor + // Close the new peer channel to wake up peer_supervisor + if (new_peer_channel_) { + new_peer_channel_->close(); + } + + // Stop acceptor - this causes run_inbound() to exit if (acceptor_) { std::error_code ec; acceptor_->close(ec); } - // Stop all peers + // Stop all peers - this causes peer->run() to exit, which allows + // peer_supervisor's peer_tasks.join() to complete manager_.stop_all(); + // Save banlist to file (final save before shutdown) + banlist_.save(); + // hosts_ saves to file in destructor - // Stop thread pool - pool_.stop(); + // NOTE: We do NOT call pool_.stop() here! + // With structured concurrency, all coroutines will complete naturally: + // 1. run_inbound() exits (acceptor closed) + // 2. run_outbound() exits (stopped_ = true) + // 3. peer_supervisor() exits after peer_tasks.join() completes + // 4. run() returns, then join() can complete + // Calling pool_.stop() here would abort pending work and prevent clean shutdown. } void p2p_node::join() { @@ -130,6 +200,29 @@ message_dispatcher& p2p_node::dispatcher() { return dispatcher_; } +banlist& p2p_node::bans() { + return banlist_; +} + +banlist const& p2p_node::bans() const { + return banlist_; +} + +void p2p_node::ban_peer( + peer_session::ptr const& peer, + std::chrono::seconds duration, + ban_reason reason) +{ + if (peer) { + banlist_.ban(peer->authority(), duration, reason); + peer->stop(error::channel_stopped); + } +} + +bool p2p_node::is_banned(infrastructure::config::authority const& authority) const { + return banlist_.is_banned(authority); +} + // ============================================================================= // Message Dispatcher implementation // ============================================================================= @@ -137,7 +230,7 @@ message_dispatcher& p2p_node::dispatcher() { ::asio::awaitable message_dispatcher::dispatch(peer_session& peer, raw_message const& msg) { auto const& command = msg.heading.command(); - spdlog::debug("[dispatcher] Dispatching '{}' from [{}]", command, peer.authority()); + spdlog::debug("[dispatcher] Dispatching '{}' from [{}]", command, peer.authority_with_agent()); // Look for specific handler auto it = handlers_.find(command); @@ -162,7 +255,7 @@ ::asio::awaitable message_dispatcher::dispatch(peer_session& peer, raw_mes } // No handler - just continue - spdlog::trace("[dispatcher] Unhandled message '{}' from [{}]", command, peer.authority()); + spdlog::trace("[dispatcher] Unhandled message '{}' from [{}]", command, peer.authority_with_agent()); co_return true; } @@ -212,36 +305,53 @@ awaitable_expected p2p_node::connect( } auto peer = *result; + auto const ip = peer->authority().asio_ip(); - // Start the session's message pump - ::asio::co_spawn(executor, peer->run(), ::asio::detached); - - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); + // Check if already connected to this IP + if (co_await manager_.exists_by_ip(ip)) { + spdlog::debug("[p2p_node] Already connected to IP {}, skipping", ip.to_string()); + peer->stop(); + co_return std::unexpected(error::address_in_use); + } - // Perform handshake - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); + // Check banlist before proceeding + if (banlist_.is_banned(peer->authority())) { + spdlog::debug("[p2p_node] Rejecting connection to banned peer {}:{}", host, port); + peer->stop(); + co_return std::unexpected(error::address_blocked); + } - if (!handshake_result) { + // Create response channel for handshake result + auto response_channel = std::make_shared(executor, 1); + + // Send peer to supervisor for FULL lifecycle management (structured concurrency) + // The supervisor will do: peer->run() && (handshake && protocols) + // This eliminates the need for detached coroutines entirely! + if (new_peer_channel_ && new_peer_channel_->is_open()) { + co_await new_peer_channel_->async_send( + std::error_code{}, + peer_event{peer, peer_direction::outbound, response_channel}, + ::asio::use_awaitable); + } else { peer->stop(); - spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", - host, port, handshake_result.error().message()); - co_return std::unexpected(handshake_result.error()); + co_return std::unexpected(error::service_stopped); } - spdlog::info("[p2p_node] Handshake complete with {}:{}, version {}", - host, port, handshake_result->negotiated_version); + // Wait for supervisor to complete handshake and send result + auto [recv_ec, response] = co_await response_channel->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); - // Add to peer manager - auto ec = co_await manager_.add(peer); - if (ec != error::success) { - peer->stop(); - co_return std::unexpected(ec); + if (recv_ec || response.result != error::success) { + // Handshake failed - peer is already stopped by supervisor + auto err = recv_ec ? error::channel_stopped : response.result; + spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", + host, port, err.message()); + co_return std::unexpected(err); } - // Start protocol handlers - ::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); + spdlog::info("[p2p_node] Connection complete with {}:{}, version {}, {}", + host, port, peer->negotiated_version(), + peer->peer_version()->user_agent()); co_return peer; } @@ -286,57 +396,47 @@ std::vector p2p_node::get_peers() const { ::asio::awaitable p2p_node::run_seeding() { spdlog::info("[p2p_node] Starting seeding from {} seeds", settings_.seeds.size()); - spdlog::debug("[p2p_node] run_seeding: before seeds check"); if (settings_.seeds.empty()) { spdlog::info("[p2p_node] No seeds configured"); co_return; } - spdlog::debug("[p2p_node] run_seeding: getting executor"); - auto executor = co_await ::asio::this_coro::executor; - spdlog::debug("[p2p_node] run_seeding: got executor"); - - // Track seeds completed - auto seeds_completed = std::make_shared>(0); - auto const total_seeds = settings_.seeds.size(); - spdlog::debug("[p2p_node] run_seeding: total_seeds = {}", total_seeds); + // Use pool's executor for parallel DNS resolution, not this_coro::executor + // (which might be a single-threaded io_context from the caller) + auto executor = pool_.get_executor(); // Copy seeds to avoid reference issues in coroutines - spdlog::debug("[p2p_node] run_seeding: copying seeds"); std::vector seeds_copy( settings_.seeds.begin(), settings_.seeds.end()); - spdlog::debug("[p2p_node] run_seeding: seeds copied, count = {}", seeds_copy.size()); - // Launch seed connections in parallel - for (size_t i = 0; i < seeds_copy.size(); ++i) { - if (stopped_) break; + // Use task_group for structured concurrency - no detached! + task_group seed_tasks(executor); - auto const& seed = seeds_copy[i]; - spdlog::debug("[p2p_node] run_seeding: processing seed {} of {}", i + 1, seeds_copy.size()); + // Track seeds completed for early exit + auto seeds_completed = std::make_shared>(0); + auto const total_seeds = seeds_copy.size(); - auto seed_host = seed.host(); - auto seed_port = seed.port(); - spdlog::debug("[p2p_node] run_seeding: seed {}:{}", seed_host, seed_port); + // Launch all seed connections in parallel + for (auto const& seed : seeds_copy) { + if (stopped_) break; - // Use member function instead of lambda to avoid capture lifetime issues - spdlog::debug("[p2p_node] run_seeding: about to co_spawn connect_to_seed for {}:{}", seed_host, seed_port); - ::asio::co_spawn(executor, - connect_to_seed(std::move(seed_host), seed_port, seeds_completed), - ::asio::detached); - spdlog::debug("[p2p_node] run_seeding: co_spawned connect_to_seed"); + seed_tasks.spawn([this, host = seed.host(), port = seed.port(), seeds_completed]() -> ::asio::awaitable { + co_await connect_to_seed(host, port, seeds_completed); + }); } - spdlog::debug("[p2p_node] run_seeding: all seed tasks spawned, entering wait loop"); + spdlog::debug("[p2p_node] run_seeding: {} seed tasks spawned", seeds_copy.size()); - // Wait for seeds with simple timeout + // Wait for seeds with early exit conditions + // We use a timer loop to check for early exit while tasks run + ::asio::steady_timer check_timer(executor); auto const max_wait = std::chrono::seconds(settings_.connect_timeout_seconds + 35); auto const start_time = std::chrono::steady_clock::now(); - while (*seeds_completed < total_seeds && !stopped_) { + while (seed_tasks.has_active_tasks() && !stopped_) { // Check elapsed time - auto elapsed = std::chrono::steady_clock::now() - start_time; - if (elapsed >= max_wait) { + if (std::chrono::steady_clock::now() - start_time >= max_wait) { spdlog::debug("[p2p_node] Seeding timeout reached"); break; } @@ -348,11 +448,13 @@ ::asio::awaitable p2p_node::run_seeding() { } // Wait a bit before checking again - ::asio::steady_timer check_timer(executor); check_timer.expires_after(1s); co_await check_timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); } + // Wait for remaining tasks to complete (structured concurrency) + co_await seed_tasks.join(); + spdlog::info("[p2p_node] Seeding complete, {} addresses available", hosts_.count()); } @@ -363,7 +465,8 @@ ::asio::awaitable p2p_node::connect_to_seed( { spdlog::debug("[p2p_node] connect_to_seed: starting for {}:{}", seed_host, seed_port); - auto executor = co_await ::asio::this_coro::executor; + // Use pool's executor explicitly for parallel operations + auto executor = pool_.get_executor(); try { auto result = co_await async_connect( @@ -383,75 +486,77 @@ ::asio::awaitable p2p_node::connect_to_seed( spdlog::debug("[p2p_node] connect_to_seed: connected to {}:{}", seed_host, seed_port); auto peer = *result; - // Start the session's message pump - spdlog::debug("[p2p_node] connect_to_seed: spawning peer->run() for {}:{}", seed_host, seed_port); - ::asio::co_spawn(executor, peer->run(), ::asio::detached); - - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - - // Perform handshake - spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { - peer->stop(); - spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", - seed_host, seed_port, handshake_result.error().message()); - ++(*seeds_completed); - co_return; - } + // Run the seeding protocol using structured concurrency: + // peer->run() && seeding_protocol() + // This eliminates the need for detached coroutines! + co_await ( + peer->run() && + [&]() -> ::asio::awaitable { + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake (uses channels - run() is running in parallel!) + spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", + seed_host, seed_port, handshake_result.error().message()); + peer->stop(); + co_return; + } - spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); + spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); - // Send getaddr request - auto ec = co_await peer->send(domain::message::get_address{}); - if (ec != error::success) { - peer->stop(); - ++(*seeds_completed); - co_return; - } + // Send getaddr request + auto ec = co_await peer->send(domain::message::get_address{}); + if (ec != error::success) { + peer->stop(); + co_return; + } - // Wait for addr response with timeout - ::asio::steady_timer timer(executor); - timer.expires_after(30s); - bool got_addresses = false; + // Wait for addr response with timeout + ::asio::steady_timer timer(executor); + timer.expires_after(30s); + bool got_addresses = false; - while (!got_addresses && !peer->stopped()) { - auto msg_result = co_await ( - peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || - timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) - ); + while (!got_addresses && !peer->stopped()) { + auto msg_result = co_await ( + peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); - if (msg_result.index() == 1) { - // Timeout - break; - } + if (msg_result.index() == 1) { + // Timeout + break; + } - auto& [recv_ec, raw] = std::get<0>(msg_result); - if (recv_ec) { - break; - } + auto& [recv_ec, raw] = std::get<0>(msg_result); + if (recv_ec) { + break; + } - if (raw.heading.command() == domain::message::address::command) { - byte_reader reader(raw.payload); - auto addr_result = domain::message::address::from_data( - reader, peer->negotiated_version()); - if (addr_result) { - auto const count = addr_result->addresses().size(); - spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", - count, seed_host, seed_port); - - for (auto const& addr : addr_result->addresses()) { - hosts_.store(addr); + if (raw.heading.command() == domain::message::address::command) { + byte_reader reader(raw.payload); + auto addr_result = domain::message::address::from_data( + reader, peer->negotiated_version()); + if (addr_result) { + auto const count = addr_result->addresses().size(); + spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", + count, seed_host, seed_port); + + for (auto const& addr : addr_result->addresses()) { + hosts_.store(addr); + } + got_addresses = true; + } } - got_addresses = true; } - } - } - peer->stop(); + peer->stop(); + }() + ); } catch (std::exception const& e) { spdlog::debug("[p2p_node] Seed {} exception: {}", seed_host, e.what()); } @@ -480,6 +585,11 @@ ::asio::awaitable p2p_node::run_inbound() { acceptor_ = std::make_unique<::asio::ip::tcp::acceptor>(std::move(*listen_result)); + // Wait for peer_supervisor to be ready (deterministic synchronization) + while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { + co_await ::asio::post(executor, ::asio::use_awaitable); + } + spdlog::info("[p2p_node] Listening on port {}", settings_.inbound_port); // Accept loop @@ -497,38 +607,25 @@ ::asio::awaitable p2p_node::run_inbound() { auto peer = *result; - // Handle the new connection in a separate coroutine - ::asio::co_spawn(executor, [this, peer, executor]() -> ::asio::awaitable { - // Start the session's message pump - ::asio::co_spawn(executor, peer->run(), ::asio::detached); - - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - - // Perform handshake - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { - peer->stop(); - spdlog::debug("[p2p_node] Inbound handshake failed: {}", - handshake_result.error().message()); - co_return; - } - - spdlog::info("[p2p_node] Inbound handshake complete from {}, version {}", - peer->authority(), handshake_result->negotiated_version); - - // Add to peer manager - auto ec = co_await manager_.add(peer); - if (ec != error::success) { - peer->stop(); - co_return; - } + // Check banlist before proceeding + if (banlist_.is_banned(peer->authority())) { + spdlog::debug("[p2p_node] Rejecting inbound connection from banned peer {}", + peer->authority()); + peer->stop(); + continue; + } - // Start protocol handlers - co_await run_peer_protocols(peer); - }, ::asio::detached); + // Send peer to supervisor for FULL lifecycle management (structured concurrency) + // Supervisor will do: peer->run() && (handshake && add_to_manager && protocols) + // No response channel needed for inbound - we don't wait for handshake result + if (new_peer_channel_ && new_peer_channel_->is_open()) { + co_await new_peer_channel_->async_send( + std::error_code{}, + peer_event{peer, peer_direction::inbound, nullptr}, + ::asio::use_awaitable); + } else { + peer->stop(); + } } } @@ -567,6 +664,7 @@ ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { spdlog::debug("[p2p_node] Failed to send ping to [{}]", peer->authority()); break; } + peer->record_ping_sent(nonce); spdlog::trace("[p2p_node] Sent ping to [{}]", peer->authority()); } continue; @@ -615,88 +713,311 @@ ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { // Cleanup spdlog::debug("[p2p_node] Ending protocols for peer [{}]", peer->authority()); + spdlog::debug("[p2p_node] Calling peer->stop() for [{}]", peer->authority()); peer->stop(); + spdlog::debug("[p2p_node] Calling manager_.remove() for [{}]", peer->authority()); co_await manager_.remove(peer); + spdlog::debug("[p2p_node] manager_.remove() completed for [{}]", peer->authority()); } ::asio::awaitable p2p_node::maintain_outbound_connections() { auto executor = co_await ::asio::this_coro::executor; ::asio::steady_timer timer(executor); + // Wait for peer_supervisor to be ready (deterministic synchronization) + // The && operator starts coroutines but doesn't guarantee execution order. + while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { + // Yield to allow peer_supervisor to start + co_await ::asio::post(executor, ::asio::use_awaitable); + } + + spdlog::info("[p2p_node] maintain_outbound_connections started, target: {} peers", settings_.outbound_connections); + // Maximum number of parallel connection attempts constexpr size_t max_parallel_attempts = 8; while (!stopped_) { auto const current_count = manager_.count_snapshot(); auto const target = settings_.outbound_connections; + auto const host_count = hosts_.count(); + auto const ban_count = banlist_.size(); if (current_count < target) { // Need more connections auto const needed = target - current_count; + spdlog::debug("[p2p_node] Connections: {}/{}, hosts: {}, banned: {}", + current_count, target, host_count, ban_count); + // Always try max_parallel_attempts to find working peers faster // Many addresses may be stale, so cast a wide net auto const batch_size = max_parallel_attempts; std::vector addresses; addresses.reserve(batch_size); - for (size_t i = 0; i < batch_size && !stopped_; ++i) { + size_t skipped_banned = 0; + size_t skipped_connected = 0; + size_t skipped_pending = 0; + + // Fetch addresses, filtering out duplicates and already-connected IPs + for (size_t attempts = 0; attempts < batch_size * 3 && addresses.size() < batch_size && !stopped_; ++attempts) { domain::message::network_address addr; auto ec = hosts_.fetch(addr); if (ec) { break; } + + auto const authority = infrastructure::config::authority(addr); + auto const ip = authority.asio_ip(); + + // Skip if already pending connection to this IP + if (pending_connections_.contains(ip)) { + ++skipped_pending; + continue; + } + + // Skip if already connected to this IP + if (co_await manager_.exists_by_ip(ip)) { + ++skipped_connected; + continue; + } + + // Skip if banned + if (banlist_.is_banned(ip)) { + ++skipped_banned; + continue; + } + + // Check for duplicate IP in current batch + bool duplicate = false; + for (auto const& existing : addresses) { + if (infrastructure::config::authority(existing).asio_ip() == ip) { + duplicate = true; + break; + } + } + if (duplicate) { + continue; + } + addresses.push_back(addr); } if (addresses.empty()) { - spdlog::debug("[p2p_node] No addresses available for outbound"); + spdlog::warn("[p2p_node] No addresses available (hosts: {}, banned: {}, skipped: {} banned, {} connected, {} pending)", + host_count, ban_count, skipped_banned, skipped_connected, skipped_pending); + + // Re-seed if host pool is too low + if (host_count < settings_.host_pool_capacity / 4) { + spdlog::info("[p2p_node] Host pool low ({}), triggering re-seed...", host_count); + co_await run_seeding(); + } } else { spdlog::debug("[p2p_node] Attempting {} parallel connections (need {}, have {})", addresses.size(), needed, current_count); - // Launch connection attempts in parallel - std::vector<::asio::awaitable> tasks; - tasks.reserve(addresses.size()); - - // Track successful connections with a shared atomic counter - auto success_count = std::make_shared>(0); + // Use task_group for structured concurrency - no detached! + task_group connection_tasks(executor); for (auto const& addr : addresses) { - auto task = [this, addr, success_count]() -> ::asio::awaitable { + auto const authority = infrastructure::config::authority(addr); + auto const ip = authority.asio_ip(); + + // Add to pending connections before spawning + pending_connections_.insert(ip); + + connection_tasks.spawn([this, addr, ip]() -> ::asio::awaitable { auto const authority = infrastructure::config::authority(addr); spdlog::trace("[p2p_node] Attempting connection to {}", authority); auto result = co_await connect(authority.to_hostname(), authority.port()); + // Remove from pending connections when done + pending_connections_.erase(ip); + if (!result) { spdlog::trace("[p2p_node] Connection failed to {}: {}", authority, result.error().message()); hosts_.remove(addr); } else { spdlog::debug("[p2p_node] Connected to {}", authority); - ++(*success_count); } - }; - - // Spawn each connection attempt - ::asio::co_spawn(executor, task(), ::asio::detached); + }); } - // Give connection attempts time to complete - // Use a shorter wait since they're running in parallel - timer.expires_after(std::chrono::seconds(settings_.connect_timeout_seconds + 2)); - co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + // Wait for ALL connection attempts to complete (structured concurrency!) + co_await connection_tasks.join(); // Continue loop to check if we need more connections continue; } } - // Wait before next check when we have enough connections - timer.expires_after(std::chrono::seconds(30)); - co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + // Wait before next check + // Use shorter interval when we're below target to recover faster from bans + // Keep wait_time short to allow quick shutdown response + auto const wait_time = (current_count < target) + ? std::chrono::milliseconds(500) // Fast retry when below target + : std::chrono::seconds(5); // Normal check when at target + + // Log status periodically when at target + if (current_count >= target) { + spdlog::debug("[p2p_node] Connections at target: {}/{}, hosts: {}, banned: {}", + current_count, target, host_count, ban_count); + } + + timer.expires_after(wait_time); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled (shutdown) + } + } +} + +// ============================================================================= +// Peer Supervisor (Structured Concurrency) +// ============================================================================= +// +// The peer_supervisor manages all peer lifecycles using the nursery pattern. +// Instead of spawning detached coroutines for each peer, all peer tasks are +// tracked in a task_group and properly awaited on shutdown. +// +// Flow: +// 1. run_inbound() and connect() send peer_events to new_peer_channel_ +// 2. peer_supervisor receives events and spawns peer tasks into task_group +// 3. On stop(), stop_signal_ is triggered +// 4. peer_supervisor stops accepting new peers and waits for all tasks to complete +// +// ============================================================================= + +::asio::awaitable p2p_node::peer_supervisor() { + spdlog::debug("[p2p_node] peer_supervisor started"); + + task_group peer_tasks(pool_.get_executor()); + + // Track ALL spawned peers (including those not yet in manager) + // This is needed for clean shutdown - manager_.stop_all() only stops + // peers that completed handshake, but we need to stop ALL peers. + std::vector all_spawned_peers; + + // Signal that we're ready to receive peers (deterministic synchronization) + supervisor_ready_.store(true, std::memory_order_release); + + while (!stopped_) { + // Wait for new peer event + // NOTE: We don't use || with stop_signal_ because the || operator in asio + // waits for BOTH operations to complete, not just the first one. + // Instead, stop() closes new_peer_channel_ which causes async_receive to return error. + auto [ec, event] = co_await new_peer_channel_->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + // Channel closed (stop() was called) or error - exit + spdlog::debug("[p2p_node] peer_supervisor channel closed: {}", ec.message()); + break; + } + + auto peer = event.peer; + auto direction = event.direction; + auto response_channel = event.response_channel; + + // Track this peer for shutdown + all_spawned_peers.push_back(peer); + + spdlog::debug("[p2p_node] peer_supervisor received {} peer [{}]", + direction == peer_direction::inbound ? "inbound" : "outbound", + peer->authority()); + + // Spawn FULL peer lifecycle into the task group (tracked, not detached!) + // This runs: peer->run() && (handshake && add_to_manager && protocols) + // The && operator ensures both branches run in parallel and we wait for both. + // When peer disconnects, both exit and && completes. + peer_tasks.spawn([this, peer, direction, response_channel]() -> ::asio::awaitable { + try { + co_await ( + peer->run() && + [&]() -> ::asio::awaitable { + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + + // Perform handshake (uses channels - run() is already running!) + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + spdlog::debug("[p2p_node] Handshake failed for [{}]: {}", + peer->authority(), handshake_result.error().message()); + // Send failure response if caller is waiting + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{handshake_result.error()}); + } + peer->stop(); + co_return; + } + + // Add to peer manager + auto add_ec = co_await manager_.add(peer); + if (add_ec != error::success) { + spdlog::debug("[p2p_node] Failed to add peer [{}] to manager: {}", + peer->authority(), add_ec.message()); + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{add_ec}); + } + peer->stop(); + co_return; + } + + // Send initial ping to get latency data + { + uint64_t ping_nonce = 0; + pseudo_random::fill(reinterpret_cast(&ping_nonce), sizeof(ping_nonce)); + domain::message::ping ping_msg(ping_nonce); + auto ec = co_await peer->send(ping_msg); + if (ec == error::success) { + peer->record_ping_sent(ping_nonce); + } + } + + // Send success response to caller + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{error::success}); + } + + // Run protocols until peer disconnects + co_await run_peer_protocols(peer); + }() + ); + } catch (std::exception const& e) { + spdlog::debug("[p2p_node] Peer [{}] task exception: {}", + peer->authority(), e.what()); + // Send error response if caller is still waiting + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{error::operation_failed}); + } + } + + spdlog::debug("[p2p_node] Peer [{}] full lifecycle completed", peer->authority()); + }); } + + spdlog::debug("[p2p_node] peer_supervisor stopping {} spawned peers before join", + all_spawned_peers.size()); + + // Stop ALL spawned peers (including those not yet in manager) + // This ensures peers still in handshake phase are also stopped, + // allowing their run() to exit and peer_tasks.join() to complete. + for (auto& peer : all_spawned_peers) { + peer->stop(); + } + + spdlog::debug("[p2p_node] peer_supervisor waiting for {} active peer tasks", + peer_tasks.active_count()); + + // CRITICAL: Wait for all peer tasks to complete + // This is the structured concurrency guarantee - no orphaned tasks! + co_await peer_tasks.join(); + + spdlog::debug("[p2p_node] peer_supervisor finished - all peer tasks completed"); } uint64_t p2p_node::generate_nonce() { diff --git a/src/network/src/peer_manager.cpp b/src/network/src/peer_manager.cpp index 35c1cbca..d51aee49 100644 --- a/src/network/src/peer_manager.cpp +++ b/src/network/src/peer_manager.cpp @@ -92,29 +92,48 @@ ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { co_return; } + spdlog::debug("[peer_manager] remove() called for peer [{}]", peer->authority()); + auto nonce = peer->nonce(); if (nonce == 0) { auto const& auth = peer->authority(); nonce = std::hash{}(auth.to_string()); } + spdlog::debug("[peer_manager] remove() calling remove_by_nonce for peer [{}]", peer->authority()); co_await remove_by_nonce(nonce); + spdlog::debug("[peer_manager] remove() completed for peer [{}]", peer->authority()); } ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { + // Note: With structured concurrency, remove() is called from peer tasks + // that are tracked by task_group. The peer_supervisor waits for all tasks + // to complete before shutdown finishes, so this operation is safe. + // We don't check stopped() because we want cleanup to proceed normally. + + spdlog::debug("[peer_manager] remove_by_nonce() starting co_spawn on strand for nonce {}", nonce); + co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { + spdlog::debug("[peer_manager] remove_by_nonce() inside strand lambda for nonce {}", nonce); auto it = peers_.find(nonce); if (it != peers_.end()) { spdlog::debug("[peer_manager] Removed peer [{}], remaining: {}", it->second->authority(), peers_.size() - 1); peers_.erase(it); count_.store(peers_.size()); + } else { + spdlog::debug("[peer_manager] Peer with nonce {} not found in map", nonce); } co_return; }, ::asio::use_awaitable); + + spdlog::debug("[peer_manager] remove_by_nonce() co_spawn completed for nonce {}", nonce); } ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { + if (stopped()) { + co_return false; + } co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { co_return peers_.find(nonce) != peers_.end(); }, ::asio::use_awaitable); @@ -123,6 +142,9 @@ ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { ::asio::awaitable peer_manager::exists_by_authority( infrastructure::config::authority const& authority) const { + if (stopped()) { + co_return false; + } co_return co_await ::asio::co_spawn(strand_, [this, &authority]() -> ::asio::awaitable { for (auto const& [nonce, peer] : peers_) { if (peer->authority() == authority) { @@ -133,7 +155,24 @@ ::asio::awaitable peer_manager::exists_by_authority( }, ::asio::use_awaitable); } +::asio::awaitable peer_manager::exists_by_ip(::asio::ip::address const& ip) const { + if (stopped()) { + co_return false; + } + co_return co_await ::asio::co_spawn(strand_, [this, &ip]() -> ::asio::awaitable { + for (auto const& [nonce, peer] : peers_) { + if (peer->authority().asio_ip() == ip) { + co_return true; + } + } + co_return false; + }, ::asio::use_awaitable); +} + ::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) const { + if (stopped()) { + co_return nullptr; + } co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { auto it = peers_.find(nonce); if (it != peers_.end()) { @@ -144,6 +183,9 @@ ::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) } ::asio::awaitable> peer_manager::all() const { + if (stopped()) { + co_return std::vector{}; + } co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable> { std::vector result; result.reserve(peers_.size()); @@ -155,6 +197,9 @@ ::asio::awaitable> peer_manager::all() const { } ::asio::awaitable peer_manager::count() const { + if (stopped()) { + co_return 0; + } co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable { co_return peers_.size(); }, ::asio::use_awaitable); @@ -188,8 +233,9 @@ void peer_manager::stop_all() { spdlog::debug("[peer_manager] Stopping all peers"); - // Post to strand to safely iterate and clean up - // Note: Callers should run the io_context to ensure completion + // Post to strand to safely stop all peers and clear the map. + // Note: With structured concurrency, peer tasks may still call remove() after + // this, but remove() handles "not found" gracefully (just does nothing). ::asio::post(strand_, [this]() { for (auto& [nonce, peer] : peers_) { peer->stop(); diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp index aad53b6e..db55e1ca 100644 --- a/src/network/src/peer_session.cpp +++ b/src/network/src/peer_session.cpp @@ -5,8 +5,12 @@ #include #include +#include +#include #include +#include + #include #include @@ -20,6 +24,40 @@ using namespace kth::domain::message; namespace { +// Map from long client name to short name for logging +// "/Bitcoin Cash Node:28.0.1(EB32.0)/" -> "BCHN:28.0.1" +boost::unordered_flat_map const known_clients = { + {"Bitcoin Cash Node:", "BCHN"}, + {"Knuth:", "KTH"}, + {"Bitcoin ABC:", "ABC"}, + {"BitcoinUnlimited:", "BU"}, + {"BCH Unlimited:", "BU"}, + {"BUCash:", "BU"}, +}; + +// Summarize user agent for logging +std::string summarize_user_agent(std::string const& user_agent) { + if (user_agent.empty()) { + return "Unknown"; + } + + for (auto const& [search, short_name] : known_clients) { + auto pos = user_agent.find(search); + if (pos != std::string::npos) { + // Extract version: starts after the search string, ends at '(' or '/' or end + auto version_start = pos + search.size(); + auto version_end = user_agent.find_first_of("(/", version_start); + if (version_end == std::string::npos) { + version_end = user_agent.size(); + } + auto version = user_agent.substr(version_start, version_end - version_start); + return std::format("{}:{}", short_name, version); + } + } + + return "Other"; +} + // Helper to extract authority from socket infrastructure::config::authority extract_authority(::asio::ip::tcp::socket const& socket) { boost_code ec; @@ -36,7 +74,7 @@ infrastructure::config::authority extract_authority(::asio::ip::tcp::socket cons // Construction / Destruction // ============================================================================= -peer_session::peer_session(socket_type socket, settings const& settings) +peer_session::peer_session(socket_type socket, settings const& settings, bool inbound) : socket_(std::move(socket)) , strand_(socket_.get_executor()) , outbound_(strand_, 100) // Buffer up to 100 outbound messages @@ -56,9 +94,11 @@ peer_session::peer_session(socket_type socket, settings const& settings) , inactivity_timeout_(std::chrono::minutes(settings.channel_inactivity_minutes)) , expiration_timeout_(std::chrono::minutes(settings.channel_expiration_minutes)) , version_(settings.protocol_maximum) + , inbound_connection_(inbound) , heading_buffer_(heading::maximum_size()) { - spdlog::debug("[peer_session] Constructor completed, authority: {}", authority()); + spdlog::debug("[peer_session] Constructor completed, authority: {}, inbound: {}", + authority(), inbound_connection_); } peer_session::~peer_session() { @@ -111,6 +151,8 @@ void peer_session::stop(code const& ec) { // Close channels outbound_.close(); inbound_.close(); + headers_responses_.close(); + block_responses_.close(); // Shutdown socket boost_code ignore; @@ -166,6 +208,13 @@ infrastructure::config::authority const& peer_session::authority() const { return authority_; } +std::string peer_session::authority_with_agent() const { + if ( ! short_user_agent_.empty()) { + return std::format("{} {}", authority_.to_string(), short_user_agent_); + } + return authority_.to_string(); +} + uint32_t peer_session::negotiated_version() const { return version_.load(); } @@ -179,9 +228,16 @@ domain::message::version::const_ptr peer_session::peer_version() const { } void peer_session::set_peer_version(domain::message::version::const_ptr value) { + if (value) { + short_user_agent_ = summarize_user_agent(value->user_agent()); + } peer_version_.store(std::move(value)); } +std::string const& peer_session::short_user_agent() const { + return short_user_agent_; +} + uint64_t peer_session::nonce() const { return nonce_.load(); } @@ -198,6 +254,118 @@ void peer_session::set_notify(bool value) { notify_.store(value); } +bool peer_session::is_inbound() const { + return inbound_connection_; +} + +bool peer_session::is_outbound() const { + return !inbound_connection_; +} + +bool peer_session::is_full_node() const { + auto version = peer_version(); + if (!version) { + return false; // Unknown, assume not full node + } + + // BCHN: fClient = !(services & NODE_NETWORK) && !(services & NODE_NETWORK_LIMITED) + // A full node has NODE_NETWORK or NODE_NETWORK_LIMITED + auto const services = version->services(); + using svc = domain::message::version::service; + return (services & svc::node_network) != 0 + || (services & svc::node_network_limited) != 0; +} + +bool peer_session::is_client() const { + return !is_full_node(); +} + +bool peer_session::is_one_shot() const { + return one_shot_.load(std::memory_order_relaxed); +} + +void peer_session::set_one_shot(bool value) { + one_shot_.store(value, std::memory_order_relaxed); +} + +bool peer_session::has_permission(permission_flags flag) const { + auto const flags = permission_flags(permission_flags_.load(std::memory_order_relaxed)); + return ::kth::network::has_permission(flags, flag); +} + +permission_flags peer_session::permissions() const { + return permission_flags(permission_flags_.load(std::memory_order_relaxed)); +} + +void peer_session::set_permissions(permission_flags flags) { + permission_flags_.store(uint32_t(flags), std::memory_order_relaxed); +} + +void peer_session::add_permission(permission_flags flag) { + auto current = permission_flags_.load(std::memory_order_relaxed); + auto const new_flags = current | uint32_t(flag); + permission_flags_.store(new_flags, std::memory_order_relaxed); +} + +void peer_session::clear_permission(permission_flags flag) { + auto current = permission_flags_.load(std::memory_order_relaxed); + auto const new_flags = current & ~uint32_t(flag); + permission_flags_.store(new_flags, std::memory_order_relaxed); +} + +bool peer_session::is_preferred_download() const { + // BCHN: fPreferredDownload = (!fInbound || HasPermission(PF_NOBAN)) + // && !fOneShot && !fClient + return (is_outbound() || has_permission(permission_flags::noban)) + && !is_one_shot() + && !is_client(); +} + +// ============================================================================= +// Statistics (lock-free, benign data races acceptable) +// ============================================================================= + +size_t peer_session::bytes_received() const { + return bytes_received_.load(std::memory_order_relaxed); +} + +size_t peer_session::bytes_sent() const { + return bytes_sent_.load(std::memory_order_relaxed); +} + +uint32_t peer_session::ping_latency_ms() const { + return ping_latency_ms_.load(std::memory_order_relaxed); +} + +void peer_session::record_ping_sent(uint64_t nonce) { + // Store time as nanoseconds since steady_clock epoch for lock-free access + auto const now = std::chrono::steady_clock::now(); + auto const ns = std::chrono::duration_cast( + now.time_since_epoch()).count(); + pending_ping_time_ns_.store(ns, std::memory_order_relaxed); + pending_ping_nonce_.store(nonce, std::memory_order_relaxed); +} + +bool peer_session::record_pong_received(uint64_t nonce) { + auto const expected_nonce = pending_ping_nonce_.load(std::memory_order_relaxed); + if (expected_nonce == 0 || nonce != expected_nonce) { + return false; + } + + auto const sent_ns = pending_ping_time_ns_.load(std::memory_order_relaxed); + auto const now = std::chrono::steady_clock::now(); + auto const now_ns = std::chrono::duration_cast( + now.time_since_epoch()).count(); + auto const latency_ms = static_cast((now_ns - sent_ns) / 1'000'000); + ping_latency_ms_.store(latency_ms, std::memory_order_relaxed); + pending_ping_nonce_.store(0, std::memory_order_relaxed); + return true; +} + +std::chrono::steady_clock::time_point peer_session::connection_time() const { + return connection_time_; +} + // ============================================================================= // Internal Coroutines // ============================================================================= @@ -254,6 +422,9 @@ ::asio::awaitable peer_session::write_loop() { co_return; } + // Track bytes sent + bytes_sent_.fetch_add(bytes_written, std::memory_order_relaxed); + spdlog::trace("[peer_session] Sent {} bytes to [{}]", bytes_written, authority()); } } @@ -355,16 +526,28 @@ awaitable_expected peer_session::read_message() { // Validate checksum if required if (validate_checksum_ && head.checksum() != bitcoin_checksum(payload)) { spdlog::warn("[peer_session] Invalid checksum for {} from [{}]", - head.command(), authority()); + head.command(), authority_with_agent()); co_return std::unexpected(error::bad_stream); } + // Track bytes received (header + payload) + bytes_received_.fetch_add(heading::maximum_size() + head.payload_size(), std::memory_order_relaxed); + spdlog::debug("[peer_session] Received {} from [{}] ({} bytes)", - head.command(), authority(), head.payload_size()); + head.command(), authority_with_agent(), head.payload_size()); co_return raw_message{head, std::move(payload)}; } +// ============================================================================= +// Direct I/O (for handshake before run() starts) +// ============================================================================= + +awaitable_expected peer_session::read_message_direct() { + // Just delegate to the private read_message() implementation + return read_message(); +} + void peer_session::signal_activity() { activity_signaled_ = true; // Cancel and restart the inactivity timer @@ -384,38 +567,108 @@ awaitable_expected async_connect( { using namespace ::asio::experimental::awaitable_operators; - // Create resolver - ::asio::ip::tcp::resolver resolver(executor); + // Try to parse hostname as IP address first (skip DNS for IPs) + std::error_code ip_parse_ec; + auto ip_address = ::asio::ip::make_address(hostname, ip_parse_ec); + + ::asio::ip::tcp::endpoint direct_endpoint; + bool is_ip_address = !ip_parse_ec; + + if (is_ip_address) { + // Hostname is already an IP address, skip DNS resolution + direct_endpoint = ::asio::ip::tcp::endpoint(ip_address, port); + spdlog::debug("[async_connect] {} is an IP address, skipping DNS", hostname); + } else { + // Need DNS resolution + auto resolver = std::make_shared<::asio::ip::tcp::resolver>(executor); + + // DNS resolution timeout (5 seconds should be plenty for DNS) + auto dns_timer = std::make_shared<::asio::steady_timer>(executor); + dns_timer->expires_after(std::chrono::seconds(5)); + + auto start_time = std::chrono::steady_clock::now(); + spdlog::debug("[async_connect] Starting DNS resolution for {} with 5s timeout", hostname); + + // Use a channel to get the first result (DNS or timeout) + auto result_channel = std::make_shared, + std::error_code + > + >>(executor, 1); + + // Spawn DNS resolution + ::asio::co_spawn(executor, [resolver, hostname, port, result_channel]() -> ::asio::awaitable { + auto [ec, endpoints] = co_await resolver->async_resolve( + hostname, std::to_string(port), ::asio::as_tuple(::asio::use_awaitable)); + result_channel->try_send(std::error_code{}, + std::variant, std::error_code>{ + std::make_tuple(ec, endpoints)}); + }, ::asio::detached); + + // Spawn timer + ::asio::co_spawn(executor, [dns_timer, result_channel]() -> ::asio::awaitable { + auto [ec] = co_await dns_timer->async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + result_channel->try_send(std::error_code{}, + std::variant, std::error_code>{ + std::make_error_code(std::errc::timed_out)}); + } + }, ::asio::detached); + + // Wait for first result + auto [recv_ec, result] = co_await result_channel->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); - // Resolve hostname - auto [resolve_ec, endpoints] = co_await resolver.async_resolve( - hostname, - std::to_string(port), - ::asio::as_tuple(::asio::use_awaitable)); + auto elapsed = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start_time).count(); + + // Cancel whichever didn't complete + resolver->cancel(); + dns_timer->cancel(); + + if (recv_ec) { + spdlog::debug("[async_connect] DNS channel error for {}: {}", hostname, recv_ec.message()); + co_return std::unexpected(error::resolve_failed); + } + + // Check which result we got + if (result.index() == 1) { + // Timeout + spdlog::debug("[async_connect] DNS resolution for {} timed out after {}ms", hostname, elapsed); + co_return std::unexpected(error::resolve_failed); + } - if (resolve_ec) { - spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); - co_return std::unexpected(error::resolve_failed); + auto [resolve_ec, endpoints] = std::get<0>(result); + spdlog::debug("[async_connect] DNS completed for {} in {}ms, ec={}", hostname, elapsed, resolve_ec.message()); + + if (resolve_ec) { + spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); + co_return std::unexpected(error::resolve_failed); + } + + // Use first resolved endpoint + direct_endpoint = *endpoints.begin(); } - // Create socket and timer for timeout + // Create socket and timer for connection timeout ::asio::ip::tcp::socket socket(executor); ::asio::steady_timer timer(executor); timer.expires_after(timeout); - // Race: connect vs timeout - auto result = co_await ( - ::asio::async_connect(socket, endpoints, ::asio::as_tuple(::asio::use_awaitable)) || + // Race: connect vs timeout (use single endpoint connect) + auto connect_result = co_await ( + socket.async_connect(direct_endpoint, ::asio::as_tuple(::asio::use_awaitable)) || timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) ); - if (result.index() == 1) { + if (connect_result.index() == 1) { // Timeout won spdlog::debug("[async_connect] Connection to {}:{} timed out", hostname, port); co_return std::unexpected(error::channel_timeout); } - auto [connect_ec, endpoint] = std::get<0>(result); + auto [connect_ec] = std::get<0>(connect_result); if (connect_ec) { spdlog::debug("[async_connect] Failed to connect to {}:{}: {}", hostname, port, connect_ec.message()); @@ -424,8 +677,19 @@ awaitable_expected async_connect( spdlog::debug("[async_connect] Connected to {}:{}", hostname, port); spdlog::debug("[async_connect] Creating peer_session..."); - auto session = std::make_shared(std::move(socket), settings); + // Outbound connection (we connected to them) + auto session = std::make_shared(std::move(socket), settings, /*inbound=*/false); spdlog::debug("[async_connect] peer_session created, authority: {}", session->authority()); + + // Apply whitelist permissions (BCHN-style) + auto flags = settings.get_whitelist_permissions(session->authority()); + if (flags != permission_flags::none) { + flags = settings.apply_legacy_whitelist_permissions(flags); + session->set_permissions(flags); + spdlog::debug("[async_connect] Applied whitelist permissions to [{}]: {}", + session->authority(), uint32_t(flags)); + } + co_return session; } @@ -465,7 +729,19 @@ awaitable_expected async_accept( endpoint.address().to_string(), endpoint.port()); } - co_return std::make_shared(std::move(socket), settings); + // Inbound connection (they connected to us) + auto session = std::make_shared(std::move(socket), settings, /*inbound=*/true); + + // Apply whitelist permissions (BCHN-style) + auto flags = settings.get_whitelist_permissions(session->authority()); + if (flags != permission_flags::none) { + flags = settings.apply_legacy_whitelist_permissions(flags); + session->set_permissions(flags); + spdlog::debug("[async_accept] Applied whitelist permissions to [{}]: {}", + session->authority(), uint32_t(flags)); + } + + co_return session; } awaitable_expected<::asio::ip::tcp::acceptor> async_listen( diff --git a/src/network/src/protocols_coro.cpp b/src/network/src/protocols_coro.cpp index 1cd5d7b7..c852c14a 100644 --- a/src/network/src/protocols_coro.cpp +++ b/src/network/src/protocols_coro.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include @@ -219,6 +221,132 @@ awaitable_expected perform_handshake( co_return handshake_result{peer_version, negotiated}; } +// ============================================================================= +// Direct Handshake (no message pump required) +// ============================================================================= +// +// This version of handshake reads/writes directly to the socket without +// needing peer->run() to be running. This enables structured concurrency +// by eliminating the need to spawn run() with detached before handshake. +// +// After handshake completes, the peer is sent to peer_supervisor which +// spawns run() + protocols in a tracked task_group. +// +// ============================================================================= + +awaitable_expected perform_handshake_direct( + peer_session& peer, + handshake_config const& config) +{ + auto const& authority = peer.authority(); + + spdlog::debug("[protocol] Starting direct handshake with [{}]", authority); + + // Send our version message (directly to socket) + auto version_msg = make_version_message(config, authority); + auto send_ec = co_await peer.send_direct(version_msg); + if (send_ec != error::success) { + spdlog::debug("[protocol] Failed to send version to [{}]", authority); + co_return std::unexpected(send_ec); + } + + // We need to receive both version and verack from the peer + // The order may vary, so we track what we've received + bool got_version = false; + bool got_verack = false; + domain::message::version::const_ptr peer_version; + + auto deadline = std::chrono::steady_clock::now() + config.timeout; + auto executor = co_await ::asio::this_coro::executor; + + while (!got_version || !got_verack) { + auto remaining = std::chrono::duration_cast( + deadline - std::chrono::steady_clock::now()); + + if (remaining <= 0s) { + spdlog::debug("[protocol] Handshake timeout with [{}]", authority); + co_return std::unexpected(error::channel_timeout); + } + + // Read message directly from socket with timeout + // Use racing pattern with timer + ::asio::steady_timer timer(executor, remaining); + + auto result = co_await ( + peer.read_message_direct() || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + // Check which completed first + if (result.index() == 1) { + // Timer won - timeout + spdlog::debug("[protocol] Handshake timeout with [{}]", authority); + co_return std::unexpected(error::channel_timeout); + } + + // Message received + auto& msg_result = std::get<0>(result); + if (!msg_result) { + spdlog::debug("[protocol] Failed to receive message from [{}]: {}", + authority, msg_result.error().message()); + co_return std::unexpected(msg_result.error()); + } + + auto const& raw = *msg_result; + auto const& command = raw.heading.command(); + + if (command == domain::message::version::command && !got_version) { + // Parse version message + byte_reader reader(raw.payload); + auto version_result = domain::message::version::from_data(reader, peer.negotiated_version()); + if (!version_result) { + spdlog::debug("[protocol] Failed to parse version from [{}]", authority); + co_return std::unexpected(error::bad_stream); + } + auto version = std::make_shared(std::move(*version_result)); + + spdlog::debug("[protocol] Received version from [{}] protocol ({}) user agent: {}", + authority, version->value(), version->user_agent()); + + // Validate + if (!validate_peer_version(*version, config, authority)) { + co_return std::unexpected(error::channel_stopped); + } + + peer_version = version; + got_version = true; + + // Send verack in response (directly to socket) + auto verack_ec = co_await peer.send_direct(domain::message::verack{}); + if (verack_ec != error::success) { + spdlog::debug("[protocol] Failed to send verack to [{}]", authority); + co_return std::unexpected(verack_ec); + } + } + else if (command == domain::message::verack::command && !got_verack) { + spdlog::debug("[protocol] Received verack from [{}]", authority); + got_verack = true; + } + else { + // Unexpected message during handshake - log but continue + spdlog::debug("[protocol] Unexpected message '{}' during handshake with [{}]", + command, authority); + } + } + + // Calculate negotiated version + auto negotiated = std::min(peer_version->value(), config.protocol_version); + + // Update peer session + peer.set_peer_version(peer_version); + peer.set_negotiated_version(negotiated); + + spdlog::debug("[protocol] Direct handshake complete with [{}], negotiated version {}", + authority, negotiated); + + co_return handshake_result{peer_version, negotiated}; +} + handshake_config make_handshake_config( settings const& network_settings, uint32_t current_height, @@ -542,6 +670,108 @@ awaitable_expected request_block( } } +awaitable_expected> request_blocks_batch( + peer_session& peer, + std::vector> const& blocks, + std::chrono::seconds timeout) +{ + if (blocks.empty()) { + co_return std::vector{}; + } + + // Build hash -> height lookup map + boost::unordered_flat_map expected_blocks; + expected_blocks.reserve(blocks.size()); + + // Build inventory list for getdata + domain::message::inventory_vector::list inventories; + inventories.reserve(blocks.size()); + + for (auto const& [height, hash] : blocks) { + expected_blocks[hash] = height; + inventories.emplace_back(domain::message::inventory_vector::type_id::block, hash); + } + + domain::message::get_data request(std::move(inventories)); + + spdlog::debug("[protocol] Requesting {} blocks in batch from [{}] ({}-{})", + blocks.size(), peer.authority(), + blocks.front().first, blocks.back().first); + + // Send ONE getdata with all block hashes + auto ec = co_await peer.send(request); + if (ec != error::success) { + co_return std::unexpected(ec); + } + + // Receive blocks as they arrive + auto executor = co_await ::asio::this_coro::executor; + auto deadline = std::chrono::steady_clock::now() + timeout; + + std::vector received_blocks; + received_blocks.reserve(blocks.size()); + + while (received_blocks.size() < blocks.size()) { + auto remaining = std::chrono::duration_cast( + deadline - std::chrono::steady_clock::now()); + + if (remaining <= 0s) { + spdlog::debug("[protocol] Timeout waiting for batch blocks from [{}] ({}/{} received)", + peer.authority(), received_blocks.size(), blocks.size()); + co_return std::unexpected(error::channel_timeout); + } + + ::asio::steady_timer timer(executor, remaining); + + auto result = co_await ( + peer.block_responses().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + spdlog::debug("[protocol] Timeout waiting for batch blocks from [{}]", peer.authority()); + co_return std::unexpected(error::channel_timeout); + } + + auto& [recv_ec, raw] = std::get<0>(result); + if (recv_ec) { + co_return std::unexpected(error::channel_stopped); + } + + // Parse the block + byte_reader reader(raw.payload); + auto block_result = domain::message::block::from_data(reader, peer.negotiated_version()); + if (!block_result) { + spdlog::debug("[protocol] Failed to parse block from [{}]", peer.authority()); + co_return std::unexpected(error::bad_stream); + } + + // Look up the height for this block + auto const block_hash = block_result->header().hash(); + auto it = expected_blocks.find(block_hash); + if (it == expected_blocks.end()) { + // Not a block we requested - ignore (could be from another request) + spdlog::trace("[protocol] Received unexpected block from [{}], ignoring", + peer.authority()); + continue; + } + + auto height = it->second; + expected_blocks.erase(it); + + received_blocks.push_back({height, std::move(*block_result)}); + } + + // Sort by height for caller convenience + std::sort(received_blocks.begin(), received_blocks.end(), + [](auto const& a, auto const& b) { return a.height < b.height; }); + + spdlog::debug("[protocol] Received {} blocks in batch from [{}]", + received_blocks.size(), peer.authority()); + + co_return received_blocks; +} + // ----------------------------------------------------------------------------- // Inventory Protocol // ----------------------------------------------------------------------------- diff --git a/src/network/src/settings.cpp b/src/network/src/settings.cpp index ac1ca138..0c757f41 100644 --- a/src/network/src/settings.cpp +++ b/src/network/src/settings.cpp @@ -31,12 +31,13 @@ settings::settings() , connect_batch_size(5) , connect_timeout_seconds(5) , channel_handshake_seconds(6000) - , channel_heartbeat_minutes(5) + , channel_heartbeat_minutes(2) // BCHN: PING_INTERVAL = 2 minutes , channel_inactivity_minutes(10) , channel_expiration_minutes(60) , channel_germination_seconds(30) , host_pool_capacity(1000) , hosts_file("hosts.cache") + , banlist_file("banlist.dat") , self(unspecified_network_address) // , bitcoin_cash(false) @@ -85,6 +86,9 @@ settings::settings(domain::config::network context) seeds.emplace_back("dnsseed.electroncash.de", 8333); // Electroncash.de seeds.emplace_back("bchseed.c3-soft.com", 8333); // C3 Soft (NilacTheGrim) seeds.emplace_back("bch.bitjson.com", 8333); // Jason Dreyzehner + + // // TODO(fernando): TEMPORARY - hardcoded peer for testing + // peers.emplace_back("194.14.247.36", 8333); #else identifier = netmagic::btc_mainnet; seeds.reserve(6); diff --git a/src/node-exe/src/main.cpp b/src/node-exe/src/main.cpp index e762668d..a9979a17 100644 --- a/src/node-exe/src/main.cpp +++ b/src/node-exe/src/main.cpp @@ -2,22 +2,23 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include +#include #include - #include -#include -#include #include +#include #include #include #include -#include #include #include #include -#include "version.hpp" +#include + #include "tui_dashboard.hpp" KTH_USE_MAIN @@ -30,25 +31,70 @@ std::string version() { void do_help(kth::node::parser& metadata, std::ostream& output) { auto const options = metadata.load_options(); - kth::infrastructure::config::printer help(options, application_name, KTH_INFORMATION_MESSAGE); + kth::infrastructure::config::printer help(options, application_name, "Runs a Bitcoin Cash full-node."); help.initialize(); help.commandline(output); } void do_settings(kth::node::parser& metadata, std::ostream& output) { auto const settings = metadata.load_settings(); - kth::infrastructure::config::printer print(settings, application_name, KTH_SETTINGS_MESSAGE); + kth::infrastructure::config::printer print(settings, application_name, "These are the configuration settings that can be set."); print.initialize(); print.settings(output); } +// Global signal state for run_with_log +namespace { + std::atomic g_signal_received{0}; + + extern "C" void log_mode_signal_handler(int signal_number) { + // std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); + // std::fflush(stderr); + g_signal_received.store(signal_number); + } +} + bool run_with_log(kth::node::executor& host) { // Traditional log mode - scrolling output - return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { - if (ec != kth::error::success) { - host.signal_stop(); - } - }); + + // Install signal handler IMMEDIATELY so Ctrl-C works during startup + g_signal_received.store(0); + auto prev_sigint = std::signal(SIGINT, log_mode_signal_handler); + auto prev_sigterm = std::signal(SIGTERM, log_mode_signal_handler); + + // Start node (blocks until ready) + auto ec = host.start(); + if (ec != kth::error::success) { + // Restore handlers + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + return false; + } + + // Check if signal was received during startup + if (g_signal_received.load() != 0) { + spdlog::info("[node] Signal received during startup, stopping..."); + host.stop(); + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + return true; + } + + // Wait for SIGINT/SIGTERM (poll the atomic) + while (g_signal_received.load() == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + spdlog::info("[node] Stop signal detected (code: {}).", g_signal_received.load()); + + // Stop node (blocks until stopped) + host.stop(); + + // Restore handlers + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + + return true; } bool run_with_tui(kth::node::executor& host) { @@ -63,10 +109,10 @@ bool run_with_tui(kth::node::executor& host) { // Set initial status kth::node_exe::node_status status; - status.version = KTH_NODE_VERSION; + status.version = std::string(kth::version); status.network_name = "BCH Mainnet"; // TODO: get from config status.state = kth::node_exe::node_status::sync_state::starting; - status.start_time = std::chrono::system_clock::now(); // Initialize start time + status.start_time = std::chrono::system_clock::now(); dashboard->update_status(status); // Start TUI @@ -77,44 +123,33 @@ bool run_with_tui(kth::node::executor& host) { return run_with_log(host); // Fallback to log mode } - // Run node (non-blocking) - bool init_ok = host.init_run(version(), kth::node::start_modules::all, [&host, &dashboard, &status](std::error_code const& ec) { - if (ec != kth::error::success) { - status.state = kth::node_exe::node_status::sync_state::error; - dashboard->update_status(status); - dashboard->request_exit(); // Signal TUI to exit on error - } - }); - - if (!init_ok) { + // Start node (blocks until ready) + auto ec = host.start(); + if (ec != kth::error::success) { dashboard->stop(); return false; } - // TODO(fernando): Update dashboard periodically with node status - // This would be done via a callback mechanism from the node + // Update status to syncing headers + status.state = kth::node_exe::node_status::sync_state::syncing_headers; + dashboard->update_status(status); - // Wait for TUI exit (user pressed q or ESC, or node error) + // Wait for TUI exit (user pressed q or ESC) while (dashboard->is_running()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - // Stop node if TUI exited - if (!host.stopped()) { - host.signal_stop(); - } - + // Stop TUI first dashboard->stop(); - return host.close(); + + // Stop node (blocks until stopped) + host.stop(); + return true; } bool run_daemon(kth::node::executor& host) { - // Daemon mode - minimal output, suitable for systemd - return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { - if (ec != kth::error::success) { - host.signal_stop(); - } - }); + // Daemon mode - same as log mode but for systemd + return run_with_log(host); } bool run(kth::node::executor& host, kth::display_mode mode) { diff --git a/src/node-exe/src/tui_dashboard.cpp b/src/node-exe/src/tui_dashboard.cpp index 72ceab59..e0c9bec0 100644 --- a/src/node-exe/src/tui_dashboard.cpp +++ b/src/node-exe/src/tui_dashboard.cpp @@ -62,13 +62,14 @@ tui_dashboard::tui_dashboard() { splash_start_ = std::chrono::steady_clock::now(); // Define navigable screens (after splash) + // TODO: Only DASHBOARD and LOGS for now, others coming later navigable_screens_ = { screen_id::dashboard, - screen_id::network, - screen_id::blockchain, - screen_id::mempool, + // screen_id::network, + // screen_id::blockchain, + // screen_id::mempool, screen_id::logs, - screen_id::terminal, + // screen_id::terminal, }; // Initialize terminal with welcome message @@ -242,6 +243,21 @@ void tui_dashboard::update_status(node_status const& status) { } } +void tui_dashboard::add_log(std::string const& message) { + { + std::lock_guard lock(status_mutex_); + status_.recent_logs.push_back(message); + // Keep only last 100 logs + while (status_.recent_logs.size() > 100) { + status_.recent_logs.erase(status_.recent_logs.begin()); + } + } + auto* scr = screen_.load(); + if (scr != nullptr) { + scr->PostEvent(Event::Custom); + } +} + bool tui_dashboard::is_running() const { return running_; } @@ -514,7 +530,107 @@ Element tui_dashboard::render_dashboard() { } Element tui_dashboard::render_network_screen() { - return render_placeholder("NETWORK"); + Elements peer_rows; + + // Header row + peer_rows.push_back(hbox({ + text(" ") | size(WIDTH, EQUAL, 2), + text("ADDRESS") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 22), + text("USER AGENT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 16), + text("HEIGHT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), + text("RECV") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), + text("SENT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), + text("PING") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 8), + text("TIME") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 8), + })); + + peer_rows.push_back(separator() | color(colors::dark_gray)); + + if (status_.peers.empty()) { + peer_rows.push_back(text(" No peers connected...") | color(colors::gray) | dim); + } else { + for (auto const& peer : status_.peers) { + // Direction indicator + auto direction = peer.is_inbound ? + text("↓ ") | color(colors::kth_violet) : + text("↑ ") | color(colors::cyan); + + // Ping color based on latency + auto ping_col = peer.ping_ms == 0 ? colors::gray : + peer.ping_ms < 100 ? colors::green : + peer.ping_ms < 300 ? colors::orange : colors::red; + + auto ping_str = peer.ping_ms > 0 ? + std::to_string(peer.ping_ms) + "ms" : "-"; + + // Connected time + auto time_str = format_duration(peer.connected_duration); + // Shorten to just the most significant part + if (peer.connected_duration.count() >= 86400) { + time_str = std::to_string(peer.connected_duration.count() / 86400) + "d"; + } else if (peer.connected_duration.count() >= 3600) { + time_str = std::to_string(peer.connected_duration.count() / 3600) + "h"; + } else if (peer.connected_duration.count() >= 60) { + time_str = std::to_string(peer.connected_duration.count() / 60) + "m"; + } else { + time_str = std::to_string(peer.connected_duration.count()) + "s"; + } + + // User agent - truncate if too long + auto user_agent = peer.user_agent; + if (user_agent.length() > 14) { + user_agent = user_agent.substr(0, 14) + ".."; + } + if (user_agent.empty()) { + user_agent = "Unknown"; + } + + // Preferred indicator + auto preferred_indicator = peer.is_preferred ? + text("★") | color(colors::bch_green) | bold : + text(" "); + + peer_rows.push_back(hbox({ + direction, + text(peer.address) | color(colors::white) | size(WIDTH, EQUAL, 22), + text(user_agent) | color(colors::cyan) | size(WIDTH, EQUAL, 16), + text(format_number(peer.start_height)) | color(colors::gray) | size(WIDTH, EQUAL, 10), + text(format_bytes(peer.bytes_received)) | color(colors::green) | size(WIDTH, EQUAL, 10), + text(format_bytes(peer.bytes_sent)) | color(colors::blue) | size(WIDTH, EQUAL, 10), + text(ping_str) | color(ping_col) | size(WIDTH, EQUAL, 8), + text(time_str) | color(colors::gray) | size(WIDTH, EQUAL, 8), + })); + } + } + + // Summary footer + Elements summary; + summary.push_back(separator() | color(colors::dark_gray)); + summary.push_back(hbox({ + text("Total: ") | color(colors::gray), + text(std::to_string(status_.peers_outbound + status_.peers_inbound)) | bold | color(colors::white), + text(" peers (") | color(colors::gray), + text("↑" + std::to_string(status_.peers_outbound)) | color(colors::cyan), + text(" out, ") | color(colors::gray), + text("↓" + std::to_string(status_.peers_inbound)) | color(colors::kth_violet), + text(" in)") | color(colors::gray), + filler(), + text("Avg ping: ") | color(colors::gray), + text(status_.avg_ping_ms > 0 ? std::to_string(status_.avg_ping_ms) + "ms" : "-") | + color(status_.avg_ping_ms < 100 ? colors::green : + status_.avg_ping_ms < 300 ? colors::orange : colors::red), + })); + + return vbox({ + render_header_bar(), + separator() | color(colors::dark_gray), + window(text(" ⚡ CONNECTED PEERS ") | bold | color(colors::cyan), + vbox(peer_rows) | flex) | flex, + vbox(summary), + separator() | color(colors::dark_gray), + render_navigation_bar(), + render_footer(), + }) | border | color(colors::kth_purple); } Element tui_dashboard::render_blockchain_screen() { @@ -526,7 +642,56 @@ Element tui_dashboard::render_mempool_screen() { } Element tui_dashboard::render_logs_screen() { - return render_placeholder("LOGS"); + Elements log_lines; + + if (status_.recent_logs.empty()) { + log_lines.push_back(text(" No logs yet...") | color(colors::gray) | dim); + } else { + // Show last N logs that fit + size_t const max_visible = 20; + size_t start = status_.recent_logs.size() > max_visible ? + status_.recent_logs.size() - max_visible : 0; + + for (size_t i = start; i < status_.recent_logs.size(); ++i) { + auto const& log = status_.recent_logs[i]; + + // Color based on log level (detect from content) + Color log_color = colors::white; + if (log.find("[error]") != std::string::npos || + log.find("[ERROR]") != std::string::npos || + log.find("Error") != std::string::npos) { + log_color = colors::red; + } else if (log.find("[warn]") != std::string::npos || + log.find("[WARN]") != std::string::npos || + log.find("Warning") != std::string::npos) { + log_color = colors::orange; + } else if (log.find("[info]") != std::string::npos || + log.find("[INFO]") != std::string::npos) { + log_color = colors::cyan; + } else if (log.find("[debug]") != std::string::npos || + log.find("[DEBUG]") != std::string::npos) { + log_color = colors::gray; + } + + // Truncate long lines + std::string display_log = log; + if (display_log.length() > 100) { + display_log = display_log.substr(0, 97) + "..."; + } + + log_lines.push_back(text(display_log) | color(log_color)); + } + } + + return vbox({ + render_header_bar(), + separator() | color(colors::dark_gray), + window(text(" 📋 LOGS ") | bold | color(colors::kth_violet), + vbox(log_lines) | flex) | flex, + separator() | color(colors::dark_gray), + render_navigation_bar(), + render_footer(), + }) | border | color(colors::kth_purple); } Element tui_dashboard::render_terminal_screen() { @@ -803,8 +968,9 @@ Element tui_dashboard::render_network_panel() { Elements rows; + // Header: Peers count and listen port rows.push_back(hbox({ - text("⬡ ") | color(total_peers > 0 ? colors::green : colors::red), + text("○ ") | color(total_peers > 0 ? colors::green : colors::red), text("Peers: ") | color(colors::gray), text(std::to_string(total_peers)) | bold | color(total_peers > 0 ? colors::green : colors::red), text(" (") | color(colors::dark_gray), @@ -813,31 +979,53 @@ Element tui_dashboard::render_network_panel() { text(")") | color(colors::dark_gray), })); - rows.push_back(text("")); - rows.push_back(hbox({ - text("↓ ") | color(colors::green) | bold, - text(format_bytes_speed(status_.bytes_received)) | color(colors::green), - text(" "), - text("↑ ") | color(colors::blue) | bold, - text(format_bytes_speed(status_.bytes_sent)) | color(colors::blue), + text("Listen: ") | color(colors::gray), + text(":8333") | color(colors::white), // TODO: get from config })); - if (status_.total_bytes_received > 0 || status_.total_bytes_sent > 0) { - rows.push_back(hbox({ - text("Total: ") | color(colors::gray), - text("↓" + format_bytes(status_.total_bytes_received)) | color(colors::green) | dim, - text(" ↑" + format_bytes(status_.total_bytes_sent)) | color(colors::blue) | dim, - })); - } + rows.push_back(text("")); - if (status_.avg_ping_ms > 0) { - rows.push_back(hbox({ - text("Ping: ") | color(colors::gray), - text(std::to_string(status_.avg_ping_ms) + "ms") | color( - status_.avg_ping_ms < 100 ? colors::green : - status_.avg_ping_ms < 500 ? colors::orange : colors::red), - })); + // Connected peers header + rows.push_back(text("Connected peers:") | color(colors::gray)); + + // Show each peer + if (status_.peers.empty()) { + rows.push_back(text(" (none)") | color(colors::dark_gray) | dim); + } else { + for (auto const& peer : status_.peers) { + // Direction + std::string direction = peer.is_inbound ? "IN " : "OUT"; + auto dir_color = peer.is_inbound ? colors::kth_violet : colors::cyan; + + // User agent - truncate if needed + std::string agent = peer.user_agent; + if (agent.empty()) agent = "Unknown"; + if (agent.length() > 12) agent = agent.substr(0, 12); + + // Format: OUT ip:port UserAgent H:height ↓recv ↑sent pingms + auto ping_color = peer.ping_ms == 0 ? colors::gray : + peer.ping_ms < 200 ? colors::green : + peer.ping_ms < 500 ? colors::orange : colors::red; + + auto ping_str = peer.ping_ms > 0 ? + std::to_string(peer.ping_ms) + "ms" : "-"; + + rows.push_back(hbox({ + text(direction + " ") | color(dir_color), + text(peer.address) | color(colors::white), + text(" "), + text(agent) | color(colors::cyan), + text(" "), + text("H:" + format_number(peer.start_height)) | color(colors::gray), + text(" "), + text("↓" + format_bytes(peer.bytes_received)) | color(colors::green), + text(" "), + text("↑" + format_bytes(peer.bytes_sent)) | color(colors::blue), + text(" "), + text(ping_str) | color(ping_color), + })); + } } return window(text(" ⚡ NETWORK ") | bold | color(colors::cyan), vbox(rows) | flex) | flex; diff --git a/src/node-exe/src/tui_dashboard.hpp b/src/node-exe/src/tui_dashboard.hpp index b6edbb76..7830876f 100644 --- a/src/node-exe/src/tui_dashboard.hpp +++ b/src/node-exe/src/tui_dashboard.hpp @@ -32,6 +32,19 @@ enum class screen_id { terminal, // C64-style terminal }; +/// Per-peer information for TUI display +struct peer_info { + std::string address; // IP:port + std::string user_agent; // Short user agent (e.g., "BCHN:28.0.1") + uint32_t start_height{0}; // Peer's reported height + size_t bytes_received{0}; // Total bytes received from peer + size_t bytes_sent{0}; // Total bytes sent to peer + uint32_t ping_ms{0}; // Last ping latency in ms + bool is_inbound{false}; // true if peer connected to us + bool is_preferred{false}; // true if preferred for download (BCHN fPreferredDownload) + std::chrono::seconds connected_duration{0}; // How long connected +}; + /// Node status for TUI display - Mining focused struct node_status { // Version & Network @@ -72,6 +85,9 @@ struct node_status { size_t total_bytes_sent{0}; // total bytes size_t avg_ping_ms{0}; + // Connected peers (for Network screen) + std::vector peers; + // Mempool size_t mempool_tx_count{0}; size_t mempool_size_bytes{0}; @@ -87,6 +103,9 @@ struct node_status { size_t db_cache_size{0}; double cpu_usage{0.0}; size_t memory_usage{0}; + + // Logs (for Logs screen) + std::vector recent_logs; }; /// TUI Dashboard using FTXUI - Multi-screen with animations @@ -106,6 +125,9 @@ class tui_dashboard { /// Update node status (thread-safe) void update_status(node_status const& status); + /// Add a log message (thread-safe) + void add_log(std::string const& message); + /// Check if TUI is running bool is_running() const; diff --git a/src/node/CMakeLists.txt b/src/node/CMakeLists.txt index 9e82fdc2..cd2e6f1e 100644 --- a/src/node/CMakeLists.txt +++ b/src/node/CMakeLists.txt @@ -153,6 +153,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") src/utility/reservation.cpp src/utility/reservations.cpp + src/block_download_coordinator.cpp + src/parallel_sync.cpp + src/block_download_coordinator_v2.cpp + src/parallel_sync_v2.cpp ) endif() @@ -184,6 +188,10 @@ set(kth_headers include/kth/node/full_node.hpp include/kth/node/sync_session.hpp include/kth/node/parser.hpp + include/kth/node/block_download_coordinator.hpp + include/kth/node/parallel_sync.hpp + include/kth/node/block_download_coordinator_v2.hpp + include/kth/node/parallel_sync_v2.hpp ) add_library(${PROJECT_NAME} ${MODE} ${kth_sources} ${kth_headers}) diff --git a/src/node/data/bn.cfg b/src/node/data/bn.cfg index 6d4d8a88..c8f55735 100644 --- a/src/node/data/bn.cfg +++ b/src/node/data/bn.cfg @@ -39,8 +39,8 @@ validate_checksum = false inbound_port = 8333 # The target number of incoming network connections, defaults to 0. inbound_connections = 0 -# The target number of outgoing network connections, defaults to 2. -outbound_connections = 2 +# The target number of outgoing network connections, defaults to 8. +outbound_connections = 8 # The attempt limit for manual connection establishment, defaults to 0 (forever). manual_attempt_limit = 0 # The number of concurrent attempts to establish one connection, defaults to 5. diff --git a/src/node/include/kth/node.hpp b/src/node/include/kth/node.hpp index 8d1b8ea2..098adff4 100644 --- a/src/node/include/kth/node.hpp +++ b/src/node/include/kth/node.hpp @@ -22,7 +22,8 @@ #include #include #include -#include +#include +#include #include diff --git a/src/node/include/kth/node/block_download_coordinator.hpp b/src/node/include/kth/node/block_download_coordinator.hpp new file mode 100644 index 00000000..a8c6e58f --- /dev/null +++ b/src/node/include/kth/node/block_download_coordinator.hpp @@ -0,0 +1,235 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP +#define KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP + +// ============================================================================= +// Block Download Coordinator - Parallel Block Download Management +// ============================================================================= +// +// This class coordinates parallel block downloads across multiple peers: +// +// DESIGN: +// ------- +// - Central coordinator assigns block heights to peers +// - Each peer can have up to MAX_BLOCKS_PER_PEER blocks in-flight +// - Blocks may arrive out-of-order; buffered until ready for validation +// - Validation happens in-order via a separate pipeline +// +// FLOW: +// ----- +// 1. Peer calls claim_blocks() to get next blocks to download +// 2. Peer sends getdata for claimed blocks +// 3. Peer receives blocks and calls block_received() +// 4. Coordinator buffers out-of-order blocks +// 5. Validation pipeline consumes blocks in order +// +// RECOVERY: +// --------- +// - On peer disconnect: reassign its in-flight blocks +// - On timeout: reassign stalled blocks to other peers +// - On validation failure: stop sync and report error +// +// ============================================================================= + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace kth::node { + +/// Configuration for parallel block download +struct parallel_download_config { + /// Maximum blocks in-flight per peer (BCHN: 16) + size_t max_blocks_per_peer{16}; + + /// Global download window - max blocks ahead of validation + size_t global_window{1024}; + + /// Timeout for individual block download + std::chrono::seconds block_timeout{60}; + + /// Timeout before reassigning stalled blocks + std::chrono::seconds stall_timeout{10}; + + /// How often to check for stalled downloads + std::chrono::seconds timeout_check_interval{1}; +}; + +/// Block download coordinator - manages parallel downloads across peers +class KND_API block_download_coordinator { +public: + using block_const_ptr = domain::message::block::const_ptr; + using peer_ptr = network::peer_session::ptr; + + /// Construct coordinator for a block range + /// @param chain Blockchain for validation + /// @param organizer Header organizer (has the header index) + /// @param start_height First block to download (usually 1 for IBD) + /// @param target_height Last block to download + /// @param executor Executor for internal channel + /// @param config Download configuration + block_download_coordinator( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config const& config = {}); + + ~block_download_coordinator(); + + // Non-copyable + block_download_coordinator(block_download_coordinator const&) = delete; + block_download_coordinator& operator=(block_download_coordinator const&) = delete; + + // ------------------------------------------------------------------------- + // Peer Interface + // ------------------------------------------------------------------------- + + /// Claim blocks for a peer to download + /// @param peer The peer claiming blocks + /// @param max_count Maximum blocks to claim (typically 16) + /// @return Vector of {height, hash} pairs to download, empty if none available + [[nodiscard]] + ::asio::awaitable>> claim_blocks( + peer_ptr const& peer, + size_t max_count); + + /// Report that a block was received + /// @param height Block height + /// @param hash Block hash + /// @param block The received block + ::asio::awaitable block_received( + uint32_t height, + hash_digest const& hash, + block_const_ptr block); + + /// Report that a peer disconnected - reassign its blocks + ::asio::awaitable peer_disconnected(peer_ptr const& peer); + + // ------------------------------------------------------------------------- + // Validation Pipeline + // ------------------------------------------------------------------------- + + /// Get next block ready for validation (in-order) + /// Blocks until a block is available or sync is complete/failed + /// @return Block to validate, or nullopt if sync complete/failed + [[nodiscard]] + ::asio::awaitable>> next_block_to_validate(); + + /// Report validation result + void validation_complete(uint32_t height, code result); + + // ------------------------------------------------------------------------- + // Status & Control + // ------------------------------------------------------------------------- + + /// Check for stalled downloads and reassign + void check_timeouts(); + + /// Check if all blocks have been downloaded and validated + [[nodiscard]] + bool is_complete() const; + + /// Check if sync has failed + [[nodiscard]] + bool has_failed() const; + + /// Check if coordinator was stopped externally + [[nodiscard]] + bool is_stopped() const; + + /// Get failure error code + [[nodiscard]] + code failure_reason() const; + + /// Stop the coordinator (cancel pending operations) + void stop(); + + /// Get current progress + struct progress { + uint32_t blocks_downloaded; + uint32_t blocks_validated; + uint32_t blocks_in_flight; + uint32_t blocks_pending; // Downloaded but not yet validated + uint32_t active_peers; // Peers with blocks in-flight + uint32_t start_height; + uint32_t target_height; + std::chrono::steady_clock::time_point start_time; + }; + + [[nodiscard]] + progress get_progress() const; + +private: + // Get hash for a block height from header organizer + hash_digest get_block_hash(uint32_t height) const; + + // Try to push ready blocks to validation channel + void flush_pending_to_validation(); + + // Mark sync as failed + void set_failed(code reason); + + // Configuration + parallel_download_config config_; + + // Blockchain access + blockchain::block_chain& chain_; + blockchain::header_organizer& organizer_; + + // Range to download + uint32_t const start_height_; + uint32_t const target_height_; + + // Strand for serializing access to shared state (replaces mutex) + // All peer operations (claim_blocks, block_received, etc.) run on this strand + ::asio::strand<::asio::any_io_executor> strand_; + std::atomic stopped_{false}; + std::atomic failed_{false}; + code failure_reason_{error::success}; + + // Assignment state + uint32_t next_height_to_assign_; // Next height to assign to a peer + + // In-flight tracking: height -> {peer, request_time} + struct assignment { + peer_ptr peer; + std::chrono::steady_clock::time_point requested_at; + }; + boost::unordered_flat_map in_flight_; + + // Out-of-order buffer: height -> block + boost::unordered_flat_map pending_blocks_; + + // Validation state + uint32_t next_height_to_validate_; + std::atomic blocks_validated_{0}; + + // Timing + std::chrono::steady_clock::time_point start_time_; + + // Channel for validation pipeline + using validation_channel = ::asio::experimental::concurrent_channel< + void(std::error_code, std::pair)>; + std::unique_ptr validation_queue_; +}; + +} // namespace kth::node + +#endif // KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP diff --git a/src/node/include/kth/node/block_download_coordinator_v2.hpp b/src/node/include/kth/node/block_download_coordinator_v2.hpp new file mode 100644 index 00000000..1e3fc839 --- /dev/null +++ b/src/node/include/kth/node/block_download_coordinator_v2.hpp @@ -0,0 +1,238 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP +#define KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP + +// ============================================================================= +// Block Download Coordinator V2 - Lock-Free Parallel Block Download +// ============================================================================= +// +// Simplified coordinator using atomic operations instead of mutex/strand. +// +// DESIGN: +// ------- +// - Uses a slot-based system where each slot represents a chunk of 16 blocks +// - Slots have 3 states: FREE (0), IN_PROGRESS (1), COMPLETED (2) +// - Claim operation is lock-free using CAS +// - Timeout checker can reset stalled slots back to FREE +// - When all slots in a round are COMPLETED, advance to next round +// +// FLOW: +// ----- +// 1. Peer calls claim_chunk() to get a chunk_id +// 2. Peer calculates block range: [start + chunk_id*16, start + chunk_id*16 + 15] +// 3. Peer fetches hashes from header_index and downloads blocks +// 4. Peer calls chunk_completed(chunk_id) when done +// 5. Timeout checker periodically resets stalled IN_PROGRESS slots +// +// ============================================================================= + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace kth::node { + +/// Configuration for parallel block download v2 +struct parallel_download_config_v2 { + /// Blocks per chunk (matches Bitcoin protocol limit) + size_t chunk_size{16}; + + /// Slots per round = max_peers * multiplier + /// Higher = less frequent round resets + size_t slots_multiplier{100}; + + /// Maximum peers expected + size_t max_peers{8}; + + /// Timeout before a slot is considered stalled + std::chrono::seconds stall_timeout{30}; + + /// How often to check for stalled downloads + std::chrono::seconds timeout_check_interval{5}; +}; + +/// Lock-free block download coordinator +class KND_API block_download_coordinator_v2 { +public: + using block_const_ptr = domain::message::block::const_ptr; + + /// Slot states + enum SlotState : uint8_t { + FREE = 0, // Available for assignment + IN_PROGRESS = 1, // Assigned, waiting for completion + COMPLETED = 2 // Blocks received successfully + }; + + /// Construct coordinator for a block range + block_download_coordinator_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config_v2 const& config = {}); + + ~block_download_coordinator_v2(); + + // Non-copyable + block_download_coordinator_v2(block_download_coordinator_v2 const&) = delete; + block_download_coordinator_v2& operator=(block_download_coordinator_v2 const&) = delete; + + // ------------------------------------------------------------------------- + // Peer Interface (Lock-Free) + // ------------------------------------------------------------------------- + + /// Claim a chunk to download + /// @return chunk_id, or nullopt if sync complete + [[nodiscard]] + std::optional claim_chunk(); + + /// Get block range for a chunk + /// @return {start_height, end_height} for the chunk + [[nodiscard]] + std::pair chunk_range(uint32_t chunk_id) const; + + /// Get block hash for a height (from header index) + [[nodiscard]] + hash_digest get_block_hash(uint32_t height) const; + + /// Report that a chunk was completed successfully + void chunk_completed(uint32_t chunk_id); + + /// Report that a chunk failed (will be retried) + void chunk_failed(uint32_t chunk_id); + + // ------------------------------------------------------------------------- + // Block Reception & Validation + // ------------------------------------------------------------------------- + + /// Report a received block for validation pipeline + void block_received(uint32_t height, block_const_ptr block); + + /// Get next block ready for validation (in-order) + [[nodiscard]] + ::asio::awaitable>> next_block_to_validate(); + + /// Report validation result + void validation_complete(uint32_t height, code result); + + // ------------------------------------------------------------------------- + // Status & Control + // ------------------------------------------------------------------------- + + /// Check for stalled downloads and reset them + void check_timeouts(); + + /// Check if all blocks have been validated + [[nodiscard]] + bool is_complete() const; + + /// Check if sync has failed + [[nodiscard]] + bool has_failed() const; + + /// Check if coordinator was stopped + [[nodiscard]] + bool is_stopped() const; + + /// Get failure reason + [[nodiscard]] + code failure_reason() const; + + /// Stop the coordinator + void stop(); + + /// Progress information + struct progress { + uint32_t chunks_assigned; + uint32_t chunks_completed; + uint32_t chunks_in_progress; + uint32_t blocks_validated; + uint32_t blocks_pending; + uint32_t current_round; + uint32_t start_height; + uint32_t target_height; + uint32_t active_peers; + std::chrono::steady_clock::time_point start_time; + }; + + /// Register/unregister active download peers + void peer_started(); + void peer_stopped(); + + [[nodiscard]] + progress get_progress() const; + +private: + /// Try to advance to next round if all slots completed + void try_advance_round(); + + /// Flush pending blocks to validation channel + void flush_pending_to_validation(); + + /// Set sync as failed + void set_failed(code reason); + + /// Get current time in milliseconds + static uint64_t now_ms(); + + // Configuration + parallel_download_config_v2 config_; + size_t slots_per_round_; + + // Blockchain access + blockchain::block_chain& chain_; + blockchain::header_organizer& organizer_; + + // Range to download + uint32_t const start_height_; + uint32_t const target_height_; + uint32_t const total_chunks_; + + // ========================================================================= + // Lock-free slot management + // ========================================================================= + std::atomic round_{0}; + std::vector> slots_; + std::vector> slot_times_; // timestamp when assigned + std::atomic resetting_{false}; + + // Status + std::atomic stopped_{false}; + std::atomic failed_{false}; + code failure_reason_{error::success}; + std::atomic chunks_completed_{0}; + std::atomic blocks_validated_{0}; + std::atomic active_peers_{0}; + + // Validation pipeline - needs synchronization for out-of-order blocks + std::mutex validation_mutex_; + uint32_t next_height_to_validate_; + boost::unordered_flat_map pending_blocks_; + + // Timing + std::chrono::steady_clock::time_point start_time_; + + // Channel for validation pipeline + using validation_channel = ::asio::experimental::concurrent_channel< + void(std::error_code, std::pair)>; + std::unique_ptr validation_queue_; +}; + +} // namespace kth::node + +#endif // KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP diff --git a/src/node/include/kth/node/executor/executor.hpp b/src/node/include/kth/node/executor/executor.hpp index 618fe4b0..a4b272bc 100644 --- a/src/node/include/kth/node/executor/executor.hpp +++ b/src/node/include/kth/node/executor/executor.hpp @@ -6,8 +6,11 @@ #define KTH_NODE_EXE_EXECUTOR_HPP_ #include +#include +#include #include #include +#include #include #include @@ -18,121 +21,132 @@ #include #include +#include namespace kth::node { -struct executor { +/// Executor - manages the lifecycle of a full node +/// +/// The executor owns the io_context and runs it internally in its own thread. +/// This design allows the node to be used as a library from any language +/// (via C API) without the caller needing to manage async execution. +/// +/// Usage: +/// executor exec(config); +/// auto ec = exec.start(); // blocks until node is ready +/// // ... use node ... +/// exec.stop(); // blocks until node is stopped +/// +class executor { +public: + using start_handler = std::function; + using stop_handler = std::function; + executor(kth::node::configuration const& config, bool stdout_enabled = true); ~executor(); executor(executor const&) = delete; - void operator=(executor const&) = delete; + executor& operator=(executor const&) = delete; -#if ! defined(KTH_DB_READONLY) - bool do_initchain(std::string_view extra); -#endif + // ------------------------------------------------------------------------- + // Lifecycle - Async versions (callback-based, for C API and non-blocking use) + // ------------------------------------------------------------------------- -#if ! defined(KTH_DB_READONLY) - /// Initialize and run the node, blocking until signal or error - bool init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler); + /// Start the node asynchronously + /// @param handler Called when node is ready (or failed to start) + void start_async(start_handler handler); - /// Initialize and run the node without blocking - bool init_run(std::string_view extra, start_modules mod, kth::handle0 handler); -#endif + /// Stop the node asynchronously + /// @param handler Called when node is fully stopped (optional) + void stop_async(stop_handler handler = nullptr); - /// Signal the node to stop - void signal_stop(); + // ------------------------------------------------------------------------- + // Lifecycle - Sync versions (blocking, for simple use cases) + // ------------------------------------------------------------------------- - /// Stop and cleanup the node (must be called from main thread) - bool close(); + /// Start the node and block until ready + /// @return Error code (success if node started successfully) + [[nodiscard]] + code start(); - /// Access the full node - kth::node::full_node& node(); - kth::node::full_node const& node() const; + /// Stop the node and block until fully stopped + void stop(); + + /// Wait for stop signal (SIGINT/SIGTERM) + /// Blocks until signal received + void wait_for_stop_signal(); + + // ------------------------------------------------------------------------- + // State + // ------------------------------------------------------------------------- + + /// Check if node is currently running (started and not stopped) + [[nodiscard]] + bool running() const; + + /// Check if node has been started (may still be starting up) + [[nodiscard]] + bool started() const; /// Check if node is stopped + [[nodiscard]] bool stopped() const; - void print_version(std::string_view extra); - void initialize_output(std::string_view extra, kth::database::db_mode_type db_mode); + // ------------------------------------------------------------------------- + // Node access (only valid when running) + // ------------------------------------------------------------------------- + + [[nodiscard]] + kth::node::full_node& node(); + + [[nodiscard]] + kth::node::full_node const& node() const; + + // ------------------------------------------------------------------------- + // Initialization helpers + // ------------------------------------------------------------------------- #if ! defined(KTH_DB_READONLY) + bool do_initchain(std::string_view extra); bool init_directory(std::error_code& ec); std::error_code init_directory_if_necessary(); #endif bool verify_directory(); + void print_version(std::string_view extra); + void initialize_output(std::string_view extra, kth::database::db_mode_type db_mode); private: - bool wait_for_signal_and_close(); void print_ascii_art(); + void start_io_thread(); + void stop_io_thread(); - static - void stop(kth::code const& ec); - - static - void handle_stop(int code); - - void run_node_async(start_modules mod); - - // Termination state - static std::promise stopping_; - + // Configuration bool stdout_enabled_; kth::node::configuration config_; + + // Node instance kth::node::full_node::ptr node_; - kth::handle0 run_handler_; - // IO context for running coroutines + // IO context runs in its own thread ::asio::io_context io_context_; + using work_guard_type = ::asio::executor_work_guard<::asio::io_context::executor_type>; + std::optional work_guard_; std::thread io_thread_; - std::atomic running_{false}; -}; -// Localizable messages. -#define KTH_SETTINGS_MESSAGE "These are the configuration settings that can be set." -#define KTH_INFORMATION_MESSAGE "Runs a Bitcoin Cash full-node." -#define KTH_UNINITIALIZED_CHAIN "The {} directory is not initialized, run: kth --initchain" -#define KTH_INITIALIZING_CHAIN "Please wait while initializing {} directory..." -#define KTH_INITCHAIN_NEW "Failed to create directory {} with error, '{}'." -#define KTH_INITCHAIN_EXISTS "Failed because the directory {} already exists." -#define KTH_INITCHAIN_TRY "Failed to test directory {} with error, '{}'." -#define KTH_INITCHAIN_COMPLETE "Completed initialization." -#define KTH_INITCHAIN_FAILED "Error creating database files." - -#define KTH_NODE_INTERRUPT "Press CTRL-C to stop the node." -#define KTH_NODE_STARTING "Please wait while the node is starting..." -#define KTH_NODE_START_FAIL "Node failed to start with error, {}." -#define KTH_NODE_SEEDED "Seeding is complete." -#define KTH_NODE_STARTED "Node is started." - -#define KTH_NODE_SIGNALED "Stop signal detected (code: {})." -#define KTH_NODE_STOPPING "Please wait while the node is stopping..." -#define KTH_NODE_STOP_FAIL "Node failed to stop properly, see log." -#define KTH_NODE_STOPPED "Node stopped successfully." -#define KTH_GOOD_BYE "Good bye!" - -#define KTH_RPC_STOPPING "RPC-ZMQ service is stopping..." -#define KTH_RPC_STOPPED "RPC-ZMQ service stopped successfully" - -#define KTH_USING_CONFIG_FILE "Using config file: {}" -#define KTH_USING_DEFAULT_CONFIG "Using default configuration settings." - -#ifdef NDEBUG -#define KTH_VERSION_MESSAGE "Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}" -#else -#define KTH_VERSION_MESSAGE "Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}\n (Debug Build)" -#endif + // State tracking + enum class state { stopped, starting, running, stopping }; + std::atomic state_{state::stopped}; + + // Synchronization for sync versions + std::mutex start_mutex_; + std::condition_variable start_cv_; + code start_result_{error::success}; -#define KTH_VERSION_MESSAGE_INIT "Knuth v{}" -#define KTH_CRYPTOCURRENCY_INIT "Currency: {} - {}." -#define KTH_MICROARCHITECTURE_INIT "Optimized for microarchitecture: {}." -#define KTH_MARCH_EXTS_INIT "Built for CPU instructions/extensions: {}." -#define KTH_DB_TYPE_INIT "Database type: {}." -#define KTH_DEBUG_BUILD_INIT "(Debug Build)" -#define KTH_NETWORK_INIT "Network: {0} ({1} - {1:#x})." -#define KTH_BLOCKCHAIN_CORES_INIT "Blockchain configured to use {} threads." -#define KTH_NETWORK_CORES_INIT "Networking configured to use {} threads." + // Tracks when run() coroutine completes (for safe shutdown) + std::promise run_completed_promise_; + std::future run_completed_future_; +}; } // namespace kth::node diff --git a/src/node/include/kth/node/full_node.hpp b/src/node/include/kth/node/full_node.hpp index 8b329a54..3ef94c2f 100644 --- a/src/node/include/kth/node/full_node.hpp +++ b/src/node/include/kth/node/full_node.hpp @@ -213,6 +213,12 @@ class KND_API full_node : public multi_crypto_setter { block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr outgoing); + // Background task coroutines (for structured concurrency) + ::asio::awaitable run_blockchain_subscriber(); +#if ! defined(__EMSCRIPTEN__) + ::asio::awaitable run_sync(); +#endif + // Configuration references (stored in configuration object) node::settings const& node_settings_; blockchain::settings const& chain_settings_; @@ -223,6 +229,7 @@ class KND_API full_node : public multi_crypto_setter { // Core components (composition, not inheritance) #if ! defined(__EMSCRIPTEN__) + kth::network::settings network_settings_; // Own copy, allows modification (e.g., user_agent) kth::network::p2p_node network_; #endif blockchain::block_chain chain_; diff --git a/src/node/include/kth/node/parallel_sync.hpp b/src/node/include/kth/node/parallel_sync.hpp new file mode 100644 index 00000000..dc138f3b --- /dev/null +++ b/src/node/include/kth/node/parallel_sync.hpp @@ -0,0 +1,44 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_PARALLEL_SYNC_HPP +#define KTH_NODE_PARALLEL_SYNC_HPP + +#include +#include +#include +#include +#include + +#include + +namespace kth::node { + +/// Result of parallel block sync +struct parallel_sync_result { + code error; + uint32_t blocks_downloaded{0}; + uint32_t blocks_validated{0}; + uint32_t final_height{0}; +}; + +/// Download and validate blocks in parallel from multiple peers +/// @param chain Blockchain for validation +/// @param organizer Header organizer (contains header index) +/// @param network P2P network for peer access +/// @param start_height First block to download +/// @param target_height Last block to download +/// @param config Download configuration +[[nodiscard]] +KND_API ::asio::awaitable parallel_block_sync( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config const& config = {}); + +} // namespace kth::node + +#endif // KTH_NODE_PARALLEL_SYNC_HPP diff --git a/src/node/include/kth/node/parallel_sync_v2.hpp b/src/node/include/kth/node/parallel_sync_v2.hpp new file mode 100644 index 00000000..0828305f --- /dev/null +++ b/src/node/include/kth/node/parallel_sync_v2.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_PARALLEL_SYNC_V2_HPP +#define KTH_NODE_PARALLEL_SYNC_V2_HPP + +#include + +#include +#include +#include +#include + +namespace kth::node { + +/// Result of parallel block sync v2 +struct parallel_sync_result_v2 { + code error{error::success}; + uint32_t blocks_downloaded{0}; + uint32_t blocks_validated{0}; + uint32_t final_height{0}; +}; + +/// Parallel block sync using lock-free coordinator v2 +/// Downloads blocks from multiple peers in parallel and validates in order +[[nodiscard]] +KND_API +::asio::awaitable parallel_block_sync_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config_v2 const& config = {}); + +} // namespace kth::node + +#endif // KTH_NODE_PARALLEL_SYNC_V2_HPP diff --git a/src/node/include/kth/node/sync_session.hpp b/src/node/include/kth/node/sync_session.hpp index 7ccb12b5..13a58abf 100644 --- a/src/node/include/kth/node/sync_session.hpp +++ b/src/node/include/kth/node/sync_session.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include @@ -57,7 +58,7 @@ struct sync_config { /// Maximum blocks to request per getdata size_t max_blocks_per_request{16}; - /// Timeout for header requests + /// Timeout for individual header request (waiting for response) std::chrono::seconds headers_timeout{30}; /// Timeout for block requests @@ -65,6 +66,37 @@ struct sync_config { /// Minimum peer protocol version for headers-first sync uint32_t minimum_version{70012}; + + // ------------------------------------------------------------------------- + // BCHN-style timeout parameters + // ------------------------------------------------------------------------- + + /// Headers download timeout base (BCHN: 15 minutes) + /// Used to calculate total allowed time for headers sync + std::chrono::seconds headers_download_timeout_base{15 * 60}; + + /// Headers download timeout per expected header (BCHN: 1ms/header) + /// Total timeout = base + per_header * expected_headers + std::chrono::microseconds headers_download_timeout_per_header{1000}; + + /// Chain sync timeout for outbound peers (BCHN: 20 minutes) + /// If peer's chain has less work than ours after this time, send getheaders + std::chrono::seconds chain_sync_timeout{20 * 60}; + + /// Headers response time after getheaders sent (BCHN: 2 minutes) + /// If peer doesn't respond with better chain after this, disconnect + std::chrono::seconds headers_response_timeout{2 * 60}; + + /// Block stalling timeout (BCHN: 10 seconds for individual blocks) + /// If a block request hasn't completed in this time, reassign to another peer + std::chrono::seconds block_stalling_timeout{10}; + + /// Block download timeout base, in units of block interval (BCHN: 10 min equivalent) + /// Actual timeout = block_interval * (base + per_peer * num_other_peers) + double block_download_timeout_base{1.0}; + + /// Block download timeout per additional peer (BCHN: 5 min equivalent) + double block_download_timeout_per_peer{0.5}; }; /// Result of a sync operation @@ -73,6 +105,7 @@ struct sync_result { size_t headers_received{0}; size_t blocks_received{0}; size_t final_height{0}; + bool timed_out{false}; // True if sync failed due to timeout (peer too slow) }; /// Sync session - coordinates headers-first sync with a single peer @@ -81,11 +114,19 @@ class KND_API sync_session { using ptr = std::shared_ptr; /// Construct sync session + /// @param chain Blockchain reference + /// @param peer Primary peer for header sync + /// @param network Network type (mainnet/testnet) + /// @param config Sync configuration + /// @param target_height Override target height (0 = use peer's start_height) + /// @param p2p_node Optional p2p_node for parallel block download (nullptr = sequential) sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, - sync_config const& config = {}); + sync_config const& config = {}, + size_t target_height = 0, + network::p2p_node* p2p_node = nullptr); /// Run synchronization with peer /// Returns when synced or on error @@ -109,9 +150,13 @@ class KND_API sync_session { ::asio::awaitable sync_headers_batch(); ::asio::awaitable sync_blocks(std::vector const& hashes); + // Background task to persist headers from header_index to database + ::asio::awaitable persist_headers_to_db(size_t start_height, size_t end_height); + blockchain::block_chain& chain_; blockchain::header_organizer organizer_; network::peer_session::ptr peer_; + network::p2p_node* p2p_node_; // Optional: for parallel block download sync_config config_; size_t header_height_{0}; // Current header-sync height (from DB at start) @@ -123,15 +168,25 @@ class KND_API sync_session { // Statistics size_t total_headers_{0}; size_t total_blocks_{0}; + + // BCHN-style timeout tracking + using clock = std::chrono::steady_clock; + clock::time_point headers_sync_start_; // When headers sync started + clock::time_point headers_sync_deadline_; // Deadline for headers sync completion + bool headers_sync_timed_out_{false}; }; /// Create a sync session for a peer +/// @param target_height Override target height (0 = use peer's start_height) +/// @param p2p_node Optional p2p_node for parallel block download (nullptr = sequential) [[nodiscard]] KND_API sync_session::ptr make_sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, - sync_config const& config = {}); + sync_config const& config = {}, + size_t target_height = 0, + network::p2p_node* p2p_node = nullptr); /// Run sync with the best available peer /// Selects peer based on start_height from version message diff --git a/src/node/src/block_download_coordinator.cpp b/src/node/src/block_download_coordinator.cpp new file mode 100644 index 00000000..9881cc03 --- /dev/null +++ b/src/node/src/block_download_coordinator.cpp @@ -0,0 +1,360 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include +#include +#include + +namespace kth::node { + +block_download_coordinator::block_download_coordinator( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config const& config) + : config_(config) + , chain_(chain) + , organizer_(organizer) + , start_height_(start_height) + , target_height_(target_height) + , strand_(::asio::make_strand(executor)) + , next_height_to_assign_(start_height) + , next_height_to_validate_(start_height) + , start_time_(std::chrono::steady_clock::now()) + , validation_queue_(std::make_unique(executor, config.global_window)) +{ + spdlog::debug("[coordinator] Created for blocks {}-{} ({} blocks)", + start_height, target_height, target_height - start_height + 1); +} + +block_download_coordinator::~block_download_coordinator() { + stop(); +} + +// ============================================================================= +// Peer Interface +// ============================================================================= + +::asio::awaitable>> block_download_coordinator::claim_blocks( + peer_ptr const& peer, + size_t max_count) +{ + // Execute on strand to serialize access to shared state + co_return co_await ::asio::co_spawn(strand_, [this, peer, max_count]() -> ::asio::awaitable>> { + if (stopped_ || failed_) { + co_return std::vector>{}; + } + + // Count how many blocks this peer already has in-flight + size_t peer_in_flight = 0; + for (auto const& [height, assignment] : in_flight_) { + if (assignment.peer == peer) { + ++peer_in_flight; + } + } + + // Limit per peer + if (peer_in_flight >= config_.max_blocks_per_peer) { + spdlog::debug("[coordinator] Peer [{}] at limit ({} >= {} max)", + peer->authority(), peer_in_flight, config_.max_blocks_per_peer); + co_return std::vector>{}; + } + + size_t can_claim = std::min(max_count, config_.max_blocks_per_peer - peer_in_flight); + + // Check in-flight limit (don't count pending - those are already downloaded) + size_t total_in_flight = in_flight_.size(); + if (total_in_flight >= config_.global_window) { + spdlog::debug("[coordinator] In-flight window full for peer [{}]: {} >= {} window", + peer->authority(), total_in_flight, config_.global_window); + co_return std::vector>{}; + } + + can_claim = std::min(can_claim, config_.global_window - total_in_flight); + + std::vector> result; + result.reserve(can_claim); + + auto now = std::chrono::steady_clock::now(); + + while (result.size() < can_claim && next_height_to_assign_ <= target_height_) { + uint32_t height = next_height_to_assign_++; + + // Get hash from header organizer + auto hash = get_block_hash(height); + if (hash == null_hash) { + spdlog::warn("[coordinator] No header hash for height {}", height); + set_failed(error::not_found); + break; + } + + // Track assignment + in_flight_[height] = {peer, now}; + result.emplace_back(height, hash); + } + + if (!result.empty()) { + spdlog::debug("[coordinator] Peer [{}] claimed {} blocks ({}-{})", + peer->authority(), result.size(), + result.front().first, result.back().first); + } + + co_return result; + }, ::asio::use_awaitable); +} + +::asio::awaitable block_download_coordinator::block_received( + uint32_t height, + hash_digest const& hash, + block_const_ptr block) +{ + // Execute on strand to serialize access to shared state + co_await ::asio::co_spawn(strand_, [this, height, hash, block = std::move(block)]() -> ::asio::awaitable { + if (stopped_ || failed_) { + co_return; + } + + // Remove from in-flight + auto it = in_flight_.find(height); + if (it != in_flight_.end()) { + in_flight_.erase(it); + } + + // Store in pending buffer + pending_blocks_[height] = std::move(block); + + spdlog::trace("[coordinator] Block {} received, {} pending, next to validate: {}", + height, pending_blocks_.size(), next_height_to_validate_); + + // Try to push ready blocks to validation + flush_pending_to_validation(); + }, ::asio::use_awaitable); +} + +::asio::awaitable block_download_coordinator::peer_disconnected(peer_ptr const& peer) { + // Execute on strand to serialize access to shared state + co_await ::asio::co_spawn(strand_, [this, peer]() -> ::asio::awaitable { + // Find and remove all blocks assigned to this peer + std::vector to_reassign; + for (auto const& [height, assignment] : in_flight_) { + if (assignment.peer == peer) { + to_reassign.push_back(height); + } + } + + for (auto height : to_reassign) { + in_flight_.erase(height); + } + + if (!to_reassign.empty()) { + // Reset assignment pointer to allow these blocks to be reclaimed + // Find the minimum height that was in-flight + uint32_t min_height = *std::min_element(to_reassign.begin(), to_reassign.end()); + if (min_height < next_height_to_assign_) { + next_height_to_assign_ = min_height; + } + + spdlog::info("[coordinator] Peer [{}] disconnected, reassigning {} blocks from height {}", + peer->authority(), to_reassign.size(), min_height); + } + }, ::asio::use_awaitable); +} + +// ============================================================================= +// Validation Pipeline +// ============================================================================= + +::asio::awaitable>> +block_download_coordinator::next_block_to_validate() +{ + if (stopped_ || failed_) { + co_return std::nullopt; + } + + // Try to receive from channel + auto [ec, block_pair] = co_await validation_queue_->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + // Channel closed or error + co_return std::nullopt; + } + + co_return block_pair; +} + +void block_download_coordinator::validation_complete(uint32_t height, code result) { + if (result != error::success) { + spdlog::error("[coordinator] Validation failed at height {}: {}", + height, result.message()); + set_failed(result); + return; + } + + ++blocks_validated_; + + // Check if we're done + if (blocks_validated_.load() >= (target_height_ - start_height_ + 1)) { + spdlog::info("[coordinator] All {} blocks validated", + target_height_ - start_height_ + 1); + validation_queue_->close(); + } +} + +// ============================================================================= +// Status & Control +// ============================================================================= + +void block_download_coordinator::check_timeouts() { + // Post to strand to serialize access + ::asio::post(strand_, [this]() { + if (stopped_ || failed_) { + return; + } + + auto now = std::chrono::steady_clock::now(); + std::vector stalled; + + for (auto const& [height, assignment] : in_flight_) { + auto elapsed = std::chrono::duration_cast( + now - assignment.requested_at); + + if (elapsed > config_.stall_timeout) { + spdlog::warn("[coordinator] Block {} stalled from [{}] ({}s)", + height, assignment.peer->authority(), elapsed.count()); + stalled.push_back(height); + } + } + + // Remove stalled assignments (will be reclaimed) + for (auto height : stalled) { + in_flight_.erase(height); + } + + if (!stalled.empty()) { + // Reset assignment to lowest stalled height + uint32_t min_height = *std::min_element(stalled.begin(), stalled.end()); + if (min_height < next_height_to_assign_) { + next_height_to_assign_ = min_height; + } + spdlog::info("[coordinator] {} stalled blocks reassigned from height {}", + stalled.size(), min_height); + } + }); +} + +bool block_download_coordinator::is_complete() const { + return blocks_validated_.load() >= (target_height_ - start_height_ + 1); +} + +bool block_download_coordinator::has_failed() const { + return failed_.load(); +} + +bool block_download_coordinator::is_stopped() const { + return stopped_.load(); +} + +code block_download_coordinator::failure_reason() const { + return failure_reason_; +} + +void block_download_coordinator::stop() { + if (stopped_.exchange(true)) { + return; // Already stopped + } + + if (validation_queue_) { + validation_queue_->close(); + } +} + +block_download_coordinator::progress block_download_coordinator::get_progress() const { + // This is called from validation pipeline which is on the strand, + // so we can safely read without additional synchronization. + // For extra safety, we use atomics for frequently changing values. + + // Count unique peers with blocks in-flight + boost::unordered_flat_set unique_peers; + for (auto const& [height, assignment] : in_flight_) { + unique_peers.insert(assignment.peer); + } + + return { + .blocks_downloaded = static_cast( + (next_height_to_assign_ - start_height_) - in_flight_.size() + pending_blocks_.size()), + .blocks_validated = blocks_validated_.load(), + .blocks_in_flight = static_cast(in_flight_.size()), + .blocks_pending = static_cast(pending_blocks_.size()), + .active_peers = static_cast(unique_peers.size()), + .start_height = start_height_, + .target_height = target_height_, + .start_time = start_time_ + }; +} + +// ============================================================================= +// Private Helpers +// ============================================================================= + +hash_digest block_download_coordinator::get_block_hash(uint32_t height) const { + // Get hash from header organizer's index + return organizer_.index().get_hash(static_cast(height)); +} + +void block_download_coordinator::flush_pending_to_validation() { + // Push as many consecutive blocks as possible to validation channel + while (!pending_blocks_.empty()) { + auto it = pending_blocks_.find(next_height_to_validate_); + if (it == pending_blocks_.end()) { + // Next block not yet received + break; + } + + // Create the pair to send WITHOUT moving from pending_blocks yet + auto block_pair = std::make_pair(next_height_to_validate_, it->second); + + // Try to send to validation channel + bool sent = validation_queue_->try_send(std::error_code{}, std::move(block_pair)); + + if (!sent) { + // Channel full - block is still safe in pending_blocks, just exit + // Rate-limit this log: only log occasionally to avoid spam + static auto last_log = std::chrono::steady_clock::now(); + auto now = std::chrono::steady_clock::now(); + if (now - last_log > std::chrono::seconds(5)) { + spdlog::warn("[coordinator] Validation channel full at height {} ({} pending)", + next_height_to_validate_, pending_blocks_.size()); + last_log = now; + } + break; + } + + // Success - now remove from pending_blocks + pending_blocks_.erase(it); + ++next_height_to_validate_; + } +} + +void block_download_coordinator::set_failed(code reason) { + if (failed_.exchange(true)) { + return; // Already failed + } + + failure_reason_ = reason; + spdlog::error("[coordinator] Sync failed: {}", reason.message()); + + if (validation_queue_) { + validation_queue_->close(); + } +} + +} // namespace kth::node diff --git a/src/node/src/block_download_coordinator_v2.cpp b/src/node/src/block_download_coordinator_v2.cpp new file mode 100644 index 00000000..14bcca64 --- /dev/null +++ b/src/node/src/block_download_coordinator_v2.cpp @@ -0,0 +1,411 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include + +namespace kth::node { + +block_download_coordinator_v2::block_download_coordinator_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config_v2 const& config) + : config_(config) + , slots_per_round_(config.max_peers * config.slots_multiplier) + , chain_(chain) + , organizer_(organizer) + , start_height_(start_height) + , target_height_(target_height) + , total_chunks_((target_height - start_height + config.chunk_size) / config.chunk_size) + , slots_(slots_per_round_) + , slot_times_(slots_per_round_) + , next_height_to_validate_(start_height) + , start_time_(std::chrono::steady_clock::now()) + , validation_queue_(std::make_unique(executor, 1024)) +{ + // Initialize all slots to FREE + for (size_t i = 0; i < slots_per_round_; ++i) { + slots_[i].store(FREE, std::memory_order_relaxed); + slot_times_[i].store(0, std::memory_order_relaxed); + } + + spdlog::debug("[coordinator_v2] Created for blocks {}-{} ({} blocks, {} chunks, {} slots/round)", + start_height, target_height, target_height - start_height + 1, + total_chunks_, slots_per_round_); +} + +block_download_coordinator_v2::~block_download_coordinator_v2() { + stop(); +} + +// ============================================================================= +// Peer Interface (Lock-Free) +// ============================================================================= + +std::optional block_download_coordinator_v2::claim_chunk() { + if (stopped_.load(std::memory_order_acquire) || failed_.load(std::memory_order_acquire)) { + return std::nullopt; + } + + // Wait if round is being reset + while (resetting_.load(std::memory_order_acquire)) { + std::this_thread::yield(); + } + + uint32_t r = round_.load(std::memory_order_acquire); + + // Search for a FREE slot + for (size_t i = 0; i < slots_per_round_; ++i) { + uint8_t expected = FREE; + if (slots_[i].compare_exchange_strong(expected, IN_PROGRESS, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + // Got slot i + slot_times_[i].store(now_ms(), std::memory_order_release); + + uint32_t chunk_id = r * slots_per_round_ + i; + + // Check if this chunk is beyond our target + auto [block_start, block_end] = chunk_range(chunk_id); + if (block_start > target_height_) { + // No more chunks needed - mark as completed and return nullopt + slots_[i].store(COMPLETED, std::memory_order_release); + return std::nullopt; + } + + spdlog::debug("[coordinator_v2] Claimed chunk {} (slot {}, round {}, blocks {}-{})", + chunk_id, i, r, block_start, block_end); + + return chunk_id; + } + } + + // All slots occupied - try to advance round + // First check if all are COMPLETED + bool all_completed = true; + for (size_t i = 0; i < slots_per_round_; ++i) { + if (slots_[i].load(std::memory_order_acquire) != COMPLETED) { + all_completed = false; + break; + } + } + + if (all_completed) { + try_advance_round(); + // Retry claim after round advance + return claim_chunk(); + } + + // Some slots are IN_PROGRESS - wait for them or timeout will reset them + spdlog::debug("[coordinator_v2] All slots occupied, waiting..."); + return std::nullopt; +} + +std::pair block_download_coordinator_v2::chunk_range(uint32_t chunk_id) const { + uint32_t block_start = start_height_ + chunk_id * config_.chunk_size; + uint32_t block_end = std::min(block_start + static_cast(config_.chunk_size) - 1, target_height_); + return {block_start, block_end}; +} + +hash_digest block_download_coordinator_v2::get_block_hash(uint32_t height) const { + return organizer_.index().get_hash(static_cast(height)); +} + +void block_download_coordinator_v2::chunk_completed(uint32_t chunk_id) { + uint32_t r = chunk_id / slots_per_round_; + size_t slot = chunk_id % slots_per_round_; + + uint32_t current_round = round_.load(std::memory_order_acquire); + if (r != current_round) { + // Old round - ignore + spdlog::debug("[coordinator_v2] Chunk {} completed but from old round {} (current: {})", + chunk_id, r, current_round); + return; + } + + // Mark as completed + slots_[slot].store(COMPLETED, std::memory_order_release); + chunks_completed_.fetch_add(1, std::memory_order_relaxed); + + spdlog::debug("[coordinator_v2] Chunk {} completed (slot {})", chunk_id, slot); + + // Try to advance round if all completed + try_advance_round(); +} + +void block_download_coordinator_v2::chunk_failed(uint32_t chunk_id) { + uint32_t r = chunk_id / slots_per_round_; + size_t slot = chunk_id % slots_per_round_; + + uint32_t current_round = round_.load(std::memory_order_acquire); + if (r != current_round) { + // Old round - ignore + return; + } + + // Reset to FREE so another peer can take it + uint8_t expected = IN_PROGRESS; + if (slots_[slot].compare_exchange_strong(expected, FREE, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + spdlog::info("[coordinator_v2] Chunk {} failed, reset to FREE", chunk_id); + } +} + +// ============================================================================= +// Block Reception & Validation +// ============================================================================= + +void block_download_coordinator_v2::block_received(uint32_t height, block_const_ptr block) { + std::lock_guard lock(validation_mutex_); + + if (stopped_ || failed_) { + return; + } + + // Store in pending buffer + pending_blocks_[height] = std::move(block); + + spdlog::trace("[coordinator_v2] Block {} received, {} pending, next to validate: {}", + height, pending_blocks_.size(), next_height_to_validate_); + + // Try to push ready blocks to validation + flush_pending_to_validation(); +} + +::asio::awaitable>> +block_download_coordinator_v2::next_block_to_validate() +{ + if (stopped_ || failed_) { + co_return std::nullopt; + } + + auto [ec, block_pair] = co_await validation_queue_->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + co_return std::nullopt; + } + + co_return block_pair; +} + +void block_download_coordinator_v2::validation_complete(uint32_t height, code result) { + if (result != error::success) { + spdlog::error("[coordinator_v2] Validation failed at height {}: {}", + height, result.message()); + set_failed(result); + return; + } + + uint32_t validated = blocks_validated_.fetch_add(1, std::memory_order_relaxed) + 1; + + // Check if we're done + if (validated >= (target_height_ - start_height_ + 1)) { + spdlog::info("[coordinator_v2] All {} blocks validated", + target_height_ - start_height_ + 1); + validation_queue_->close(); + } +} + +// ============================================================================= +// Status & Control +// ============================================================================= + +void block_download_coordinator_v2::check_timeouts() { + if (stopped_ || failed_) { + return; + } + + uint64_t now = now_ms(); + uint64_t timeout_ms = std::chrono::duration_cast( + config_.stall_timeout).count(); + + for (size_t i = 0; i < slots_per_round_; ++i) { + if (slots_[i].load(std::memory_order_acquire) == IN_PROGRESS) { + uint64_t assigned_at = slot_times_[i].load(std::memory_order_acquire); + if (assigned_at > 0 && (now - assigned_at) > timeout_ms) { + // Slot stalled - reset to FREE + uint8_t expected = IN_PROGRESS; + if (slots_[i].compare_exchange_strong(expected, FREE, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + uint32_t chunk_id = round_.load(std::memory_order_acquire) * slots_per_round_ + i; + spdlog::warn("[coordinator_v2] Chunk {} (slot {}) timed out, reset to FREE", + chunk_id, i); + } + } + } + } +} + +bool block_download_coordinator_v2::is_complete() const { + auto validated = blocks_validated_.load(std::memory_order_acquire); + auto total = target_height_ - start_height_ + 1; + bool complete = validated >= total; + if (complete) { + spdlog::info("[coordinator_v2] is_complete() = true: validated={}, total={}, start={}, target={}", + validated, total, start_height_, target_height_); + } + return complete; +} + +bool block_download_coordinator_v2::has_failed() const { + return failed_.load(std::memory_order_acquire); +} + +bool block_download_coordinator_v2::is_stopped() const { + return stopped_.load(std::memory_order_acquire); +} + +code block_download_coordinator_v2::failure_reason() const { + return failure_reason_; +} + +void block_download_coordinator_v2::stop() { + if (stopped_.exchange(true, std::memory_order_acq_rel)) { + return; + } + + if (validation_queue_) { + validation_queue_->close(); + } +} + +void block_download_coordinator_v2::peer_started() { + spdlog::info("[coordinator_v2] peer_started() called on coordinator at {}", static_cast(this)); + auto prev = active_peers_.fetch_add(1, std::memory_order_relaxed); + spdlog::info("[coordinator_v2] peer_started() completed, was {}, now {}", prev, prev + 1); +} + +void block_download_coordinator_v2::peer_stopped() { + active_peers_.fetch_sub(1, std::memory_order_relaxed); +} + +block_download_coordinator_v2::progress block_download_coordinator_v2::get_progress() const { + // Count assigned and completed slots in current round + uint32_t in_progress = 0; + uint32_t completed = 0; + for (size_t i = 0; i < slots_per_round_; ++i) { + uint8_t state = slots_[i].load(std::memory_order_acquire); + if (state == IN_PROGRESS) ++in_progress; + else if (state == COMPLETED) ++completed; + } + + // Get pending blocks count + uint32_t pending = 0; + { + std::lock_guard lock(const_cast(validation_mutex_)); + pending = static_cast(pending_blocks_.size()); + } + + return { + .chunks_assigned = in_progress + completed, + .chunks_completed = chunks_completed_.load(std::memory_order_acquire), + .chunks_in_progress = in_progress, + .blocks_validated = blocks_validated_.load(std::memory_order_acquire), + .blocks_pending = pending, + .current_round = round_.load(std::memory_order_acquire), + .start_height = start_height_, + .target_height = target_height_, + .active_peers = active_peers_.load(std::memory_order_acquire), + .start_time = start_time_ + }; +} + +// ============================================================================= +// Private Helpers +// ============================================================================= + +void block_download_coordinator_v2::try_advance_round() { + // Check if all slots are COMPLETED + for (size_t i = 0; i < slots_per_round_; ++i) { + if (slots_[i].load(std::memory_order_acquire) != COMPLETED) { + return; // Not all completed + } + } + + // All completed - try to acquire reset lock + bool expected = false; + if (!resetting_.compare_exchange_strong(expected, true, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + return; // Another thread is resetting + } + + // We have the reset lock + uint32_t old_round = round_.load(std::memory_order_acquire); + uint32_t new_round = old_round + 1; + + // Check if we've processed all chunks + uint32_t chunks_in_new_round = new_round * slots_per_round_; + if (chunks_in_new_round >= total_chunks_) { + // All chunks assigned - no need to advance, sync is almost done + resetting_.store(false, std::memory_order_release); + return; + } + + spdlog::info("[coordinator_v2] Advancing to round {} (chunks {}-{})", + new_round, chunks_in_new_round, chunks_in_new_round + slots_per_round_ - 1); + + // Reset all slots to FREE + for (size_t i = 0; i < slots_per_round_; ++i) { + slots_[i].store(FREE, std::memory_order_relaxed); + slot_times_[i].store(0, std::memory_order_relaxed); + } + + // Advance round counter + round_.store(new_round, std::memory_order_release); + + // Release reset lock + resetting_.store(false, std::memory_order_release); +} + +void block_download_coordinator_v2::flush_pending_to_validation() { + // Must be called with validation_mutex_ held + + while (!pending_blocks_.empty()) { + auto it = pending_blocks_.find(next_height_to_validate_); + if (it == pending_blocks_.end()) { + break; // Next block not yet received + } + + auto block_pair = std::make_pair(next_height_to_validate_, it->second); + + bool sent = validation_queue_->try_send(std::error_code{}, std::move(block_pair)); + if (!sent) { + // Channel full - try again later + break; + } + + pending_blocks_.erase(it); + ++next_height_to_validate_; + } +} + +void block_download_coordinator_v2::set_failed(code reason) { + if (failed_.exchange(true, std::memory_order_acq_rel)) { + return; + } + + failure_reason_ = reason; + spdlog::error("[coordinator_v2] Sync failed: {}", reason.message()); + + if (validation_queue_) { + validation_queue_->close(); + } +} + +uint64_t block_download_coordinator_v2::now_ms() { + return static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch() + ).count() + ); +} + +} // namespace kth::node diff --git a/src/node/src/executor/executor.cpp b/src/node/src/executor/executor.cpp index c183e885..21817481 100644 --- a/src/node/src/executor/executor.cpp +++ b/src/node/src/executor/executor.cpp @@ -17,11 +17,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -45,275 +45,437 @@ using std::error_code; using kth::database::data_base; using std::placeholders::_1; -// static auto const application_name = "kth"; -static constexpr int initialize_stop = 0; static constexpr int directory_exists = 0; static constexpr int directory_not_found = 2; static auto const mode = std::ofstream::out | std::ofstream::app; -std::promise executor::stopping_; //NOLINT +// ============================================================================= +// Construction / Destruction +// ============================================================================= -executor::executor(kth::node::configuration const& config, bool stdout_enabled /*= true*/) +executor::executor(kth::node::configuration const& config, bool stdout_enabled) : stdout_enabled_(stdout_enabled) , config_(config) { #if ! defined(__EMSCRIPTEN__) - auto& network = config_.network; - auto const verbose = network.verbose; - - network.user_agent = get_user_agent(); - - kth::log::initialize(network.debug_file.string(), network.error_file.string(), stdout_enabled, verbose); + auto const& network = config_.network; + kth::log::initialize(network.debug_file.string(), network.error_file.string(), stdout_enabled, network.verbose); #endif // ! defined(__EMSCRIPTEN__) } executor::~executor() { - if (running_) { - signal_stop(); + // Ensure clean shutdown + if (state_.load() == state::running) { + stop(); } - // Ensure io_context is stopped and thread is joined +} + +// ============================================================================= +// IO Thread Management +// ============================================================================= + +void executor::start_io_thread() { + // Create work guard to keep io_context alive even when there's no work + work_guard_.emplace(io_context_.get_executor()); + + // Start io_context in background thread + io_thread_ = std::thread([this]() { + io_context_.run(); + }); +} + +void executor::stop_io_thread() { + spdlog::debug("[executor] stop_io_thread() - releasing work guard..."); + // Release work guard to allow io_context to stop + work_guard_.reset(); + + spdlog::debug("[executor] stop_io_thread() - stopping io_context..."); + // Stop io_context io_context_.stop(); + + spdlog::debug("[executor] stop_io_thread() - joining io thread..."); + // Wait for thread to finish if (io_thread_.joinable()) { io_thread_.join(); } + spdlog::debug("[executor] stop_io_thread() - done"); } -void executor::print_version(std::string_view extra) { - std::println(KTH_VERSION_MESSAGE, kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); -} +// ============================================================================= +// Async Lifecycle +// ============================================================================= + +void executor::start_async(start_handler handler) { + auto expected = state::stopped; + if (!state_.compare_exchange_strong(expected, state::starting)) { + if (handler) { + handler(error::operation_failed); // Already started/starting/stopping + } + return; + } + + // Initialize the run_completed promise/future pair for this run + run_completed_promise_ = std::promise(); + run_completed_future_ = run_completed_promise_.get_future(); + + // Initialize output and directory + initialize_output("", config_.database.db_mode); + + spdlog::info("[node] Press CTRL-C to stop the node."); + spdlog::info("[node] Please wait while the node is starting..."); #if ! defined(KTH_DB_READONLY) -bool executor::init_directory(error_code& ec) { - auto const& directory = config_.database.directory; + auto ec = init_directory_if_necessary(); + if (ec != error::success) { + auto const& directory = config_.database.directory; + spdlog::error("[node] Failed to create directory {} with error, '{}'.", directory.string(), ec.message()); + if (handler) { + handler(ec); + } + return; + } +#endif - if (create_directories(directory, ec)) { - spdlog::info("[node] {}", fmt::format(KTH_INITIALIZING_CHAIN, directory.string())); + // Create the node + node_ = std::make_shared(config_); - auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); - auto const& settings = config_.database; + // Start IO thread + start_io_thread(); - data_base db(settings); - auto const result = db.create(genesis); + // Spawn the startup coroutine + ::asio::co_spawn(io_context_, [this, handler]() -> ::asio::awaitable { + // Start the node + auto start_ec = co_await node_->start(); + if (start_ec != error::success) { + spdlog::error("[node] Node failed to start with error: {}.", start_ec.message()); + if (handler) { + handler(start_ec); + } + // Notify sync version + { + std::lock_guard lock(start_mutex_); + start_result_ = start_ec; + } + start_cv_.notify_all(); + // Signal run completed (early exit) so stop() doesn't hang + run_completed_promise_.set_value(); + co_return; + } - if ( ! result ) { - spdlog::info("[node] {}", KTH_INITCHAIN_FAILED); - return false; + spdlog::info("[node] Seeding is complete."); + + // Mark as running BEFORE calling run() so start() can return + // run() blocks until the node is stopped, so we must notify first + state_ = state::running; + + // Notify handler + if (handler) { + handler(error::success); } - spdlog::info("[node] {}", KTH_INITCHAIN_COMPLETE); - return true; - } + // Notify sync version so start() can return + { + std::lock_guard lock(start_mutex_); + start_result_ = error::success; + } + start_cv_.notify_all(); - return false; -} + spdlog::info("[node] Node is started."); -// CAPI -bool executor::do_initchain(std::string_view extra) { - initialize_output(extra, config_.database.db_mode); + // Run the node (starts P2P, sync, etc.) + // This blocks until the node is stopped (via stop()) + auto run_ec = co_await node_->run(); + if (run_ec != error::success && run_ec != error::service_stopped) { + spdlog::error("[node] Node run ended with error: {}.", run_ec.message()); + } - error_code ec; + spdlog::debug("[node] Node run() completed, signaling run_completed_promise."); - if (init_directory(ec)) { - return true; + // Signal that run() has completed - stop() waits for this before destroying the node + run_completed_promise_.set_value(); + + }, [this, handler](std::exception_ptr ep) { + if (ep) { + try { + std::rethrow_exception(ep); + } catch (std::exception const& e) { + spdlog::error("[node] Startup exception: {}", e.what()); + } + if (handler) { + handler(error::operation_failed); + } + // Notify sync version + { + std::lock_guard lock(start_mutex_); + start_result_ = error::operation_failed; + } + start_cv_.notify_all(); + + // Signal run completed (with error) so stop() doesn't hang + run_completed_promise_.set_value(); + } + }); +} + +void executor::stop_async(stop_handler handler) { + auto expected = state::running; + if (!state_.compare_exchange_strong(expected, state::stopping)) { + // Not running or already stopping + if (handler) { + handler(); + } + return; } - auto const& directory = config_.database.directory; + spdlog::info("[node] Please wait while the node is stopping..."); - if (ec.value() == directory_exists) { - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_EXISTS, directory.string())); - return false; + // Stop node + if (node_) { + node_->stop(); } - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); - return false; -} + // Cleanup must happen on a separate thread to avoid blocking io_context. + // The cleanup thread waits for run() to complete before calling join(). + std::thread cleanup_thread([this, handler]() { + // CRITICAL: Wait for run() to fully complete before cleanup. + // run() may still be inside chain.organize() when stop() is called. + // We must wait for all coroutines to exit before destroying resources. + spdlog::debug("[executor] Waiting for run() to complete..."); + if (run_completed_future_.valid()) { + run_completed_future_.wait(); + } + spdlog::debug("[executor] run() completed, proceeding with cleanup"); -#endif // ! defined(KTH_DB_READONLY) + // Now it's safe to join (all coroutines have exited) + if (node_) { + node_->join(); + } -kth::node::full_node& executor::node() { - return *node_; -} + spdlog::info("[node] Node stopped successfully."); + spdlog::info("[node] Good bye!"); -kth::node::full_node const& executor::node() const { - return *node_; + state_ = state::stopped; + + // Handler MUST be called LAST - caller may destroy objects after this + if (handler) { + handler(); + } + }); + cleanup_thread.detach(); } -// Close must be called from main thread. -bool executor::close() { - spdlog::info("[node] {}", KTH_NODE_STOPPING); +// ============================================================================= +// Sync Lifecycle +// ============================================================================= - if (node_) { - node_->stop(); - node_->join(); - spdlog::info("[node] {}", KTH_NODE_STOPPED); +code executor::start() { + std::unique_lock lock(start_mutex_); + + // Start async + start_async(nullptr); + + // Wait for completion with periodic wakeup + // This allows external signal handlers to interrupt us + while (!start_cv_.wait_for(lock, std::chrono::milliseconds(100), [this]() { + return state_.load() == state::running || start_result_ != error::success; + })) { + // Check if we should abort (e.g., signal received) + // The caller can check g_signal_received after start() returns } - // Stop the io_context and wait for the io thread to finish - io_context_.stop(); - if (io_thread_.joinable()) { - io_thread_.join(); + return start_result_; +} + +void executor::stop() { + if (state_.load() != state::running) { + return; } - spdlog::info("[node] {}", KTH_GOOD_BYE); - running_ = false; - return true; + std::promise done_promise; + auto done_future = done_promise.get_future(); + + stop_async([&done_promise]() { + done_promise.set_value(); + }); + + // Wait for stop_async's cleanup coroutine to complete + done_future.wait(); + + spdlog::debug("[executor] stop() - cleanup coroutine completed, waiting for run() to complete..."); + + // CRITICAL: Wait for run() coroutine to fully complete before destroying the node. + // This ensures all parallel_sync and other coroutines have finished and won't + // access destroyed objects. Without this, we get segfaults on shutdown. + if (run_completed_future_.valid()) { + run_completed_future_.wait(); + } + + spdlog::debug("[executor] stop() - run() completed, destroying node..."); + + // Destroy node BEFORE stopping io_context + // (node's components use io_context for timer cancellation, etc.) + node_.reset(); + + spdlog::debug("[executor] stop() - node destroyed, stopping io thread..."); + + // Stop IO thread + stop_io_thread(); + + spdlog::debug("[executor] stop() - io thread stopped, exiting stop()"); } -// private -bool executor::wait_for_signal_and_close() { - // Wait for stop. Ensure calling close from the main thread. - stopping_.get_future().wait(); - return close(); +// Global variable for signal handling (required for std::signal) +namespace { + std::atomic g_signal_received{0}; + std::atomic g_signal_waiting{false}; + + void signal_handler(int signal_number) { + // Immediate print to stderr (unbuffered) so user sees it right away + // Note: fprintf is async-signal-safe, std::println is not + // std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); + // std::fflush(stderr); + g_signal_received.store(signal_number); + } } -#if ! defined(KTH_DB_READONLY) +void executor::wait_for_stop_signal() { + // Mark that we're waiting for a signal + g_signal_waiting.store(true); -error_code executor::init_directory_if_necessary() { - if (verify_directory()) return error::success; + // Install signal handlers using std::signal (simpler and more reliable) + auto prev_sigint = std::signal(SIGINT, signal_handler); + auto prev_sigterm = std::signal(SIGTERM, signal_handler); - error_code ec; - if (init_directory(ec)) return error::success; + // Poll for signal (simple and reliable) + while (g_signal_received.load() == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } - return ec; + auto signal_received = g_signal_received.load(); + spdlog::info("[node] Stop signal detected (code: {}).", signal_received); + + // Restore previous handlers + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + g_signal_waiting.store(false); } -// Helper to run node in coroutine context -void executor::run_node_async(start_modules mod) { - ::asio::co_spawn(io_context_, [this, mod]() -> ::asio::awaitable { - // Start the node - auto start_ec = co_await node_->start(); - if (start_ec != error::success) { - spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, start_ec.message())); - if (run_handler_) { - run_handler_(start_ec); - } - co_return; - } +// ============================================================================= +// State +// ============================================================================= - spdlog::info("[node] {}", KTH_NODE_SEEDED); - - // Run the node (only for full mode, not just_chain) - if (mod != start_modules::just_chain) { - auto run_ec = co_await node_->run(); - if (run_ec != error::success) { - spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, run_ec.message())); - if (run_handler_) { - run_handler_(run_ec); - } - co_return; - } - } +bool executor::running() const { + return state_.load() == state::running; +} - spdlog::info("[node] {}", KTH_NODE_STARTED); +bool executor::started() const { + auto s = state_.load(); + return s == state::starting || s == state::running || s == state::stopping; +} - if (run_handler_) { - run_handler_(error::success); - } - }, ::asio::detached); +bool executor::stopped() const { + return state_.load() == state::stopped; +} - // Run the io_context in a background thread (saved for proper shutdown) - io_thread_ = std::thread([this]() { - io_context_.run(); - }); +// ============================================================================= +// Node Access +// ============================================================================= + +kth::node::full_node& executor::node() { + return *node_; } -bool executor::init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler) { - run_handler_ = std::move(handler); +kth::node::full_node const& executor::node() const { + return *node_; +} - initialize_output(extra, config_.database.db_mode); +// ============================================================================= +// Initialization Helpers +// ============================================================================= - spdlog::info("[node] {}", KTH_NODE_INTERRUPT); - spdlog::info("[node] {}", KTH_NODE_STARTING); +#if ! defined(KTH_DB_READONLY) +bool executor::init_directory(error_code& ec) { + auto const& directory = config_.database.directory; - auto ec = init_directory_if_necessary(); - if (ec != error::success) { - auto const& directory = config_.database.directory; - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); + if (create_directories(directory, ec)) { + spdlog::info("[node] Please wait while initializing {} directory...", directory.string()); - if (run_handler_) { - run_handler_(ec); - } - auto res = wait_for_signal_and_close(); - return false; - } + auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); + auto const& settings = config_.database; - // Now that the directory is verified we can create the node for it. - node_ = std::make_shared(config_); - running_ = true; + data_base db(settings); + auto const result = db.create(genesis); - // Start and run the node asynchronously - run_node_async(mod); + if (!result) { + spdlog::info("[node] Error creating database files."); + return false; + } - auto res = wait_for_signal_and_close(); - return res; -} + spdlog::info("[node] Completed initialization."); + return true; + } -bool executor::init_run(std::string_view extra, start_modules mod, kth::handle0 handler) { - run_handler_ = std::move(handler); + return false; +} +bool executor::do_initchain(std::string_view extra) { initialize_output(extra, config_.database.db_mode); - spdlog::info("[node] {}", KTH_NODE_INTERRUPT); - spdlog::info("[node] {}", KTH_NODE_STARTING); - - auto ec = init_directory_if_necessary(); - if (ec != error::success) { - auto const& directory = config_.database.directory; - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); + error_code ec; - if (run_handler_) { - run_handler_(ec); - } - return false; + if (init_directory(ec)) { + return true; } - // Now that the directory is verified we can create the node for it. - node_ = std::make_shared(config_); - running_ = true; + auto const& directory = config_.database.directory; - // Start and run the node asynchronously - run_node_async(mod); + if (ec.value() == directory_exists) { + spdlog::error("[node] Failed because the directory {} already exists.", directory.string()); + return false; + } - return true; + spdlog::error("[node] Failed to create directory {} with error, '{}'.", directory.string(), ec.message()); + return false; } -#endif // ! defined(KTH_DB_READONLY) +error_code executor::init_directory_if_necessary() { + if (verify_directory()) return error::success; -bool executor::stopped() const { - return node_ ? node_->stopped() : true; -} + error_code ec; + if (init_directory(ec)) return error::success; -// Stop signal. -// ---------------------------------------------------------------------------- + return ec; +} +#endif // ! defined(KTH_DB_READONLY) -void executor::handle_stop(int code) { - // Reinitialize after each capture to prevent hard shutdown. - // Do not capture failure signals as calling stop can cause flush lock file - // to clear due to the aborted thread dropping the flush lock mutex. - std::signal(SIGINT, handle_stop); - std::signal(SIGTERM, handle_stop); +bool executor::verify_directory() { + error_code ec; + auto const& directory = config_.database.directory; - if (code == initialize_stop) { - return; + if (exists(directory, ec)) { + return true; } - spdlog::info("[node] {}", fmt::format(KTH_NODE_SIGNALED, code)); - stop(kth::error::success); -} + if (ec.value() == directory_not_found) { + spdlog::error("[node] The {} directory is not initialized, run: kth --initchain", directory.string()); + return false; + } -void executor::signal_stop() { - stop(kth::code()); + auto const message = ec.message(); + spdlog::error("[node] Failed to test directory {} with error, '{}'.", directory.string(), message); + return false; } -// Manage the race between console stop and server stop. -void executor::stop(kth::code const& ec) { - static std::once_flag stop_mutex; - std::call_once(stop_mutex, [&](){ stopping_.set_value(ec); }); +void executor::print_version(std::string_view extra) { +#ifdef NDEBUG + std::println("Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}", + kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); +#else + std::println("Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}\n (Debug Build)", + kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); +#endif } -// Utilities. -// ---------------------------------------------------------------------------- - void executor::print_ascii_art() { std::print(R"( ... .-=*#%%= :-=+++*#: @@ -334,7 +496,6 @@ void executor::print_ascii_art() { High Performance Bitcoin Cash Node )"); - // Center version under the slogan constexpr char slogan[] = "High Performance Bitcoin Cash Node"; constexpr auto slogan_start = 10; auto version_text = std::format("v{}", kth::version); @@ -343,7 +504,6 @@ void executor::print_ascii_art() { std::println(); } -// Set up logging. void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { auto const& file = config_.file; @@ -352,9 +512,9 @@ void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { } if (file.empty()) { - spdlog::info("[node] {}", KTH_USING_DEFAULT_CONFIG); + spdlog::info("[node] Using default configuration settings."); } else { - spdlog::info("[node] {}", fmt::format(KTH_USING_CONFIG_FILE, file.string())); + spdlog::info("[node] Using config file: {}", file.string()); } std::string_view db_type_str; @@ -366,39 +526,21 @@ void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { db_type_str = KTH_DB_TYPE_PRUNED; } - spdlog::info("[node] {}", fmt::format(KTH_VERSION_MESSAGE_INIT, kth::version)); - spdlog::info("[node] {}", extra); - spdlog::info("[node] {}", fmt::format(KTH_CRYPTOCURRENCY_INIT, KTH_CURRENCY_SYMBOL_STR, KTH_CURRENCY_STR)); - spdlog::info("[node] {}", fmt::format(KTH_MICROARCHITECTURE_INIT, KTH_MICROARCHITECTURE_STR)); - spdlog::info("[node] {}", fmt::format(KTH_MARCH_EXTS_INIT, march_names())); - spdlog::info("[node] {}", fmt::format(KTH_DB_TYPE_INIT, db_type_str)); + spdlog::info("[node] Knuth v{}", kth::version); + spdlog::info("[node] Currency: {} - {}.", KTH_CURRENCY_SYMBOL_STR, KTH_CURRENCY_STR); + spdlog::info("[node] Optimized for microarchitecture: {}.", KTH_MICROARCHITECTURE_STR); + spdlog::info("[node] Built for CPU instructions/extensions: {}.", march_names()); + spdlog::info("[node] Database type: {}.", db_type_str); #ifndef NDEBUG - spdlog::info("[node] {}", KTH_DEBUG_BUILD_INIT); + spdlog::info("[node] (Debug Build)"); #endif - spdlog::info("[node] {}", fmt::format(KTH_NETWORK_INIT, name(kth::get_network(config_.network.identifier, config_.network.inbound_port == 48333)), config_.network.identifier)); - spdlog::info("[node] {}", fmt::format(KTH_BLOCKCHAIN_CORES_INIT, kth::thread_ceiling(config_.chain.cores))); - spdlog::info("[node] {}", fmt::format(KTH_NETWORK_CORES_INIT, kth::thread_ceiling(config_.network.threads))); -} - -// Use missing directory as a sentinel indicating lack of initialization. -bool executor::verify_directory() { - error_code ec; - auto const& directory = config_.database.directory; - - if (exists(directory, ec)) { - return true; - } - - if (ec.value() == directory_not_found) { - spdlog::error("[node] {}", fmt::format(KTH_UNINITIALIZED_CHAIN, directory.string())); - return false; - } - - auto const message = ec.message(); - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_TRY, directory.string(), message)); - return false; + auto const network_id = config_.network.identifier; + auto const network_type = kth::get_network(network_id, config_.network.inbound_port == 48333); + spdlog::info("[node] Network: {0} ({1} - {1:#x}).", name(network_type), network_id); + spdlog::info("[node] Blockchain configured to use {} threads.", kth::thread_ceiling(config_.chain.cores)); + spdlog::info("[node] Networking configured to use {} threads.", kth::thread_ceiling(config_.network.threads)); } } // namespace kth::node diff --git a/src/node/src/full_node.cpp b/src/node/src/full_node.cpp index f46f3a73..543bd3dd 100644 --- a/src/node/src/full_node.cpp +++ b/src/node/src/full_node.cpp @@ -13,17 +13,20 @@ #include #include #include +#include #include #include #include #include +#include namespace kth::node { using namespace kth::blockchain; using namespace kth::domain::chain; using namespace kth::domain::config; +using namespace ::asio::experimental::awaitable_operators; #if ! defined(__EMSCRIPTEN__) using namespace kth::network; @@ -40,7 +43,8 @@ full_node::full_node(configuration const& configuration) , chain_settings_(configuration.chain) , network_type_(get_network(configuration.network.identifier, configuration.network.inbound_port == 48333)) , chain_thread_pool_(configuration.chain.cores) - , network_(configuration.network) + , network_settings_(configuration.network) + , network_(network_settings_) , chain_( chain_thread_pool_, configuration.chain, @@ -61,11 +65,29 @@ full_node::full_node(configuration const& configuration) network_type_ ) #endif -{} +{ +#if ! defined(__EMSCRIPTEN__) + spdlog::debug("[full_node] configuration.network.threads = {}", configuration.network.threads); + spdlog::debug("[full_node] network_settings_.threads = {}", network_settings_.threads); + + // Set user agent after initialization (network_ holds reference to network_settings_) + std::vector features; +#if defined(KTH_CURRENCY_BCH) + features.push_back(format_eb(configuration.chain.default_consensus_block_size)); +#endif + network_settings_.user_agent = get_user_agent(features); +#endif +} full_node::~full_node() { - stop(); - join(); + spdlog::debug("[full_node] destructor starting"); + // Only stop/join if not already stopped + if (!stopped()) { + spdlog::debug("[full_node] destructor - not stopped, calling stop/join"); + stop(); + join(); + } + spdlog::debug("[full_node] destructor - about to destroy members"); } // ============================================================================= @@ -90,7 +112,7 @@ ::asio::awaitable full_node::start() { auto ec = co_await network_.start(); if (ec != error::success) { spdlog::error("[node] Failure starting network: {}", ec.message()); - chain_.stop(); + (void)chain_.stop(); co_return ec; } #endif @@ -126,76 +148,144 @@ ::asio::awaitable full_node::run() { spdlog::info("[node] Node start heights: header-sync ({}), block-sync ({}).", header_height, block_height); - // Subscribe to blockchain reorganizations +#if ! defined(__EMSCRIPTEN__) + // Run all background tasks in parallel using structured concurrency. + // This blocks until ALL tasks complete (i.e., until stop() is called). + // No detached coroutines - everything is properly awaited. + spdlog::debug("[full_node] Starting parallel tasks with && operator"); + co_await ( + run_blockchain_subscriber() && + network_.run() && + run_sync() + ); + spdlog::debug("[full_node] All parallel tasks completed"); +#else + // WASM: only blockchain subscriber (no network) + co_await run_blockchain_subscriber(); +#endif + + co_return error::success; +} + +::asio::awaitable full_node::run_blockchain_subscriber() { + spdlog::debug("[full_node] run_blockchain_subscriber() starting"); auto blockchain_channel = subscribe_blockchain(); - if (blockchain_channel) { - ::asio::co_spawn(chain_.executor(), [this, blockchain_channel]() -> ::asio::awaitable { - while (blockchain_channel->is_open() && !stopped()) { - auto result = co_await blockchain_channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); - auto& [ec, fork_height, incoming, outgoing] = result; - - if (ec) { - break; - } - - if ( ! handle_reorganized(error::success, fork_height, incoming, outgoing)) { - unsubscribe_blockchain(blockchain_channel); - break; - } - } - }, ::asio::detached); + if (!blockchain_channel) { + spdlog::debug("[full_node] run_blockchain_subscriber() - no channel, exiting"); + co_return; } + spdlog::debug("[full_node] run_blockchain_subscriber() - channel obtained, entering loop"); + + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + while (!stopped()) { + // Non-blocking try_receive + size_t fork_height{}; + block_const_ptr_list_const_ptr incoming{}; + block_const_ptr_list_const_ptr outgoing{}; + + bool received = blockchain_channel->try_receive([&](std::error_code ec, size_t fh, auto in, auto out) { + if (!ec) { + fork_height = fh; + incoming = std::move(in); + outgoing = std::move(out); + } + }); -#if ! defined(__EMSCRIPTEN__) - // Run the P2P network (starts connections and protocol handlers) - auto ec = co_await network_.run(); - if (ec != error::success) { - spdlog::error("[node] Failure running network: {}", ec.message()); - co_return ec; + if (received) { + if (!handle_reorganized(error::success, fork_height, incoming, outgoing)) { + unsubscribe_blockchain(blockchain_channel); + break; + } + } else if (!blockchain_channel->is_open()) { + // Channel closed + break; + } else { + // No data, sleep briefly + timer.expires_after(std::chrono::milliseconds(100)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled + } + } } + spdlog::debug("[full_node] run_blockchain_subscriber() exiting"); +} - // Start sync in background - // TODO(fernando): Make this configurable and add proper sync management - // TODO(fernando): blockchain::block_chain should migrate to coroutines - // (organize, fetch_*, etc.) to eliminate callbacks and std::promise usage - ::asio::co_spawn(network_.thread_pool().get_executor(), - [this]() -> ::asio::awaitable { - auto executor = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(executor); - - // Wait until we have at least one connected peer - while (!stopped() && network_.connection_count() == 0) { - timer.expires_after(std::chrono::milliseconds(500)); - co_await timer.async_wait(::asio::use_awaitable); +#if ! defined(__EMSCRIPTEN__) +::asio::awaitable full_node::run_sync() { + spdlog::debug("[full_node] run_sync() starting"); + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + while (!stopped()) { + // Wait until we have at least one connected peer + while (!stopped() && network_.connection_count() == 0) { + timer.expires_after(std::chrono::milliseconds(100)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec || stopped()) { + spdlog::debug("[full_node] run_sync() exiting"); + co_return; } - - if (stopped()) { + } + + if (stopped()) { + co_return; + } + + spdlog::info("[node] Starting initial block sync..."); + auto result = co_await sync_from_best_peer(chain_, network_, network_type_); + + if (stopped()) { + co_return; + } + + if (result.error) { + spdlog::warn("[node] Sync failed: {} (connected peers: {}), retrying...", + result.error.message(), network_.connection_count()); + // Brief delay to allow maintain_outbound_connections to find new peers + timer.expires_after(std::chrono::milliseconds(500)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec || stopped()) { co_return; } - - spdlog::info("[node] Starting initial block sync..."); - auto result = co_await sync_from_best_peer(chain_, network_, network_type_); - - if (result.error) { - spdlog::warn("[node] Initial sync failed: {}", result.error.message()); - } else { - spdlog::info("[node] Initial sync complete: {} headers, {} blocks, height {}", - result.headers_received, result.blocks_received, result.final_height); + continue; + } + + // Check if we actually synced something + if (result.headers_received > 0 || result.blocks_received > 0) { + spdlog::info("[node] Sync progress: {} headers, {} blocks, height {}", + result.headers_received, result.blocks_received, result.final_height); + // Continue syncing - there might be more blocks + if (stopped()) { + co_return; } - }, ::asio::detached); -#endif - - co_return error::success; + continue; + } + + // No sync happened - no peers ahead of us + // Wait longer before checking again (allows new peers to connect) + spdlog::debug("[node] No peers ahead of us at height {}, waiting for new peers...", + result.final_height); + timer.expires_after(std::chrono::seconds(5)); + auto [ec2] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec2 || stopped()) { + break; // Timer cancelled or stop requested + } + } + spdlog::debug("[full_node] run_sync() exiting"); } +#endif void full_node::stop() { #if ! defined(__EMSCRIPTEN__) + // IMPORTANT: Only stop the network here, NOT the chain! + // The chain must remain operational until run() completes because + // run_sync() may still be inside chain.organize() when this is called. + // chain_.stop() is called in join() after run() has fully exited. network_.stop(); #endif - - if (!chain_.stop()) { - spdlog::error("[node] Failed to stop blockchain."); - } } void full_node::join() { @@ -203,6 +293,12 @@ void full_node::join() { network_.join(); #endif + // Now that run() has exited (all coroutines done), it's safe to stop the chain. + // This must happen AFTER run() completes to avoid crashes in chain.organize(). + if (!chain_.stop()) { + spdlog::error("[node] Failed to stop blockchain."); + } + if (!chain_.close()) { spdlog::error("[node] Failed to close blockchain."); } diff --git a/src/node/src/parallel_sync.cpp b/src/node/src/parallel_sync.cpp new file mode 100644 index 00000000..bd6b35af --- /dev/null +++ b/src/node/src/parallel_sync.cpp @@ -0,0 +1,376 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace kth::node { + +namespace { + +// ============================================================================= +// Peer Download Loop +// ============================================================================= + +/// Download loop for a single peer +::asio::awaitable peer_download_loop( + block_download_coordinator& coordinator, + network::peer_session::ptr peer, + parallel_download_config const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync] Download loop STARTED for peer [{}]", + peer->authority()); + + // Check initial conditions + spdlog::debug("[parallel_sync] Peer [{}] - checking initial conditions", peer->authority()); + if (coordinator.is_complete()) { + spdlog::debug("[parallel_sync] Peer [{}] - sync already complete, exiting", + peer->authority()); + co_return; + } + if (coordinator.has_failed()) { + spdlog::debug("[parallel_sync] Peer [{}] - sync already failed, exiting", + peer->authority()); + co_return; + } + if (peer->stopped()) { + spdlog::debug("[parallel_sync] Peer [{}] - peer already stopped, exiting", + peer->authority()); + co_return; + } + + spdlog::debug("[parallel_sync] Peer [{}] - entering main loop", peer->authority()); + while (!coordinator.is_complete() && !coordinator.has_failed() && !peer->stopped()) { + // Claim blocks to download + spdlog::debug("[parallel_sync] Peer [{}] - calling claim_blocks", peer->authority()); + auto blocks = co_await coordinator.claim_blocks(peer, config.max_blocks_per_peer); + spdlog::debug("[parallel_sync] Peer [{}] - claim_blocks returned {} blocks", peer->authority(), blocks.size()); + + if (blocks.empty()) { + // No blocks available - wait a bit and retry + spdlog::debug("[parallel_sync] Peer [{}] - claim_blocks returned empty, waiting 100ms...", + peer->authority()); + ::asio::steady_timer timer(executor); + timer.expires_after(std::chrono::milliseconds(100)); + co_await timer.async_wait(::asio::use_awaitable); + continue; + } + + spdlog::info("[parallel_sync] Peer [{}] CLAIMED {} blocks ({}-{}), requesting...", + peer->authority(), blocks.size(), blocks.front().first, blocks.back().first); + + // Request all blocks in ONE getdata message (batch mode) + // This is MUCH faster than requesting one block at a time + auto batch_result = co_await network::request_blocks_batch(*peer, blocks, config.block_timeout); + + if (!batch_result) { + spdlog::warn("[parallel_sync] Failed to get blocks from peer [{}]: {}", + peer->authority(), batch_result.error().message()); + co_await coordinator.peer_disconnected(peer); + // Stop the peer so network can drop it and connect to new peers + peer->stop(batch_result.error()); + co_return; + } + + spdlog::debug("[parallel_sync] Peer [{}] received {} blocks, reporting to coordinator", + peer->authority(), batch_result->size()); + + // Report all received blocks to coordinator + for (auto& block_with_h : *batch_result) { + auto block_ptr = std::make_shared(std::move(block_with_h.block)); + // Get the original hash from the blocks vector + auto it = std::find_if(blocks.begin(), blocks.end(), + [h = block_with_h.height](auto const& p) { return p.first == h; }); + if (it != blocks.end()) { + co_await coordinator.block_received(block_with_h.height, it->second, block_ptr); + } + } + + } + + // Log why we exited + if (coordinator.is_complete()) { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: sync complete", peer->authority()); + } else if (coordinator.has_failed()) { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: sync failed", peer->authority()); + } else if (peer->stopped()) { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: peer stopped", peer->authority()); + } else { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: unknown reason", peer->authority()); + } +} + +// ============================================================================= +// Validation Pipeline +// ============================================================================= + +/// Validation pipeline - validates blocks in order +::asio::awaitable validation_pipeline( + block_download_coordinator& coordinator, + blockchain::block_chain& chain) +{ + spdlog::debug("[parallel_sync] Starting validation pipeline"); + + while (true) { + // Get next block to validate (blocks until available) + auto block_opt = co_await coordinator.next_block_to_validate(); + + if (!block_opt) { + // No more blocks or sync failed + break; + } + + auto const& [height, block] = *block_opt; + + spdlog::trace("[parallel_sync] Validating block at height {}", height); + + // Validate and store block + // Note: organize() validates the block and adds it to the chain. + // headers_pre_validated=true because this is headers-first sync. + auto result = co_await chain.organize(block, /*headers_pre_validated=*/true); + + coordinator.validation_complete(height, result); + + if (result != error::success) { + spdlog::error("[parallel_sync] Block validation failed at height {}: {}", + height, result.message()); + break; + } + + // Log progress periodically + if (height % 1000 == 0) { + auto progress = coordinator.get_progress(); + auto now = std::chrono::steady_clock::now(); + auto elapsed_secs = std::chrono::duration_cast( + now - progress.start_time).count(); + + // Calculate speed and ETA + double blocks_per_sec = elapsed_secs > 0 + ? static_cast(progress.blocks_validated) / static_cast(elapsed_secs) + : 0.0; + + uint32_t total_blocks = progress.target_height - progress.start_height + 1; + uint32_t remaining = total_blocks - progress.blocks_validated; + uint32_t eta_secs = blocks_per_sec > 0 + ? static_cast(static_cast(remaining) / blocks_per_sec) + : 0; + + // Format ETA as HH:MM:SS + uint32_t eta_hours = eta_secs / 3600; + uint32_t eta_mins = (eta_secs % 3600) / 60; + uint32_t eta_s = eta_secs % 60; + + double percent = 100.0 * static_cast(progress.blocks_validated) / + static_cast(total_blocks); + + spdlog::info("[parallel_sync] Height: {} ({:.1f}%) | {:.0f} blk/s | ETA: {:02d}:{:02d}:{:02d} | peers: {} | in-flight: {}", + height, percent, blocks_per_sec, eta_hours, eta_mins, eta_s, + progress.active_peers, progress.blocks_in_flight); + } + } + + spdlog::debug("[parallel_sync] Validation pipeline completed"); +} + +// ============================================================================= +// Timeout Checker +// ============================================================================= + +/// Periodically check for stalled downloads +::asio::awaitable timeout_checker( + block_download_coordinator& coordinator, + parallel_download_config const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + spdlog::debug("[parallel_sync] Starting timeout checker"); + + while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped()) { + timer.expires_after(config.timeout_check_interval); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled + } + + coordinator.check_timeouts(); + } + + spdlog::debug("[parallel_sync] Timeout checker completed"); +} + +} // anonymous namespace + +// ============================================================================= +// Main Parallel Sync Function +// ============================================================================= + +::asio::awaitable parallel_block_sync( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync] Starting parallel block sync from {} to {} ({} blocks)", + start_height, target_height, target_height - start_height + 1); + + // Create coordinator + block_download_coordinator coordinator( + chain, organizer, start_height, target_height, executor, config); + + // Get available peers (async version) + auto peers = co_await network.peers().all(); + if (peers.empty()) { + spdlog::error("[parallel_sync] No peers available for block download"); + co_return parallel_sync_result{ + .error = error::channel_stopped, + .blocks_downloaded = 0, + .blocks_validated = 0, + .final_height = start_height + }; + } + + spdlog::info("[parallel_sync] Using {} peers for parallel download", peers.size()); + + // ========================================================================= + // Structured concurrency with proper shutdown handling: + // - Download loops run in their own group + // - When ALL download loops exit (peers disconnect or sync complete), + // we stop the coordinator to unblock validation/timeout tasks + // ========================================================================= + + kth::task_group all_tasks(executor); + + // Spawn a "download supervisor" that: + // 1. Runs all download loops in a nested task group + // 2. Watches for new peers and adds them dynamically + // 3. When ALL download loops exit, stops the coordinator + all_tasks.spawn([&]() -> ::asio::awaitable { + kth::task_group download_tasks(executor); + + // Track which peers already have download loops (by address string) + boost::unordered_flat_set active_peers; + + // Start initial peers + for (auto const& peer : peers) { + auto addr = peer->authority().to_string(); + active_peers.insert(addr); + spdlog::info("[parallel_sync] Starting download loop for initial peer [{}]", addr); + download_tasks.spawn(peer_download_loop(coordinator, peer, config)); + } + + // Spawn a peer watcher that adds new peers as they connect + download_tasks.spawn([&]() -> ::asio::awaitable { + auto exec = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(exec); + + while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped() && !network.stopped()) { + timer.expires_after(std::chrono::seconds(2)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled + } + + // Check if network is stopping + if (network.stopped()) { + spdlog::debug("[parallel_sync] Peer watcher - network stopped, exiting"); + break; + } + + // Check for new peers and clean up dead ones + auto current_peers = co_await network.peers().all(); + + // Build set of currently connected (live) peer addresses + boost::unordered_flat_set live_addrs; + for (auto const& peer : current_peers) { + if (!peer->stopped()) { + live_addrs.insert(peer->authority().to_string()); + } + } + + // Remove dead peers from active_peers so they can reconnect + erase_if(active_peers, [&live_addrs](auto const& addr) { + return !live_addrs.contains(addr); + }); + + // Add new peers + for (auto const& peer : current_peers) { + if (peer->stopped()) { + continue; + } + auto addr = peer->authority().to_string(); + auto [it, inserted] = active_peers.insert(addr); + if (inserted) { + spdlog::debug("[parallel_sync] Spawning download loop for new peer [{}]", addr); + download_tasks.spawn(peer_download_loop(coordinator, peer, config)); + spdlog::info("[parallel_sync] Added new peer [{}] to download pool (total: {})", + addr, active_peers.size()); + } + } + } + spdlog::debug("[parallel_sync] Peer watcher exiting"); + }()); + + // Wait for all download loops to complete + co_await download_tasks.join(); + + // All downloads done - stop coordinator to unblock validation pipeline + spdlog::debug("[parallel_sync] All download loops exited, stopping coordinator"); + coordinator.stop(); + }()); + + // Spawn validation pipeline + all_tasks.spawn(validation_pipeline(coordinator, chain)); + + // Spawn timeout checker + all_tasks.spawn(timeout_checker(coordinator, config)); + + // Wait for all tasks to complete + co_await all_tasks.join(); + + // Build result + auto progress = coordinator.get_progress(); + parallel_sync_result result{ + .error = coordinator.has_failed() ? coordinator.failure_reason() : error::success, + .blocks_downloaded = progress.blocks_downloaded, + .blocks_validated = progress.blocks_validated, + .final_height = start_height + progress.blocks_validated - 1 + }; + + if (coordinator.is_complete()) { + spdlog::info("[parallel_sync] Parallel sync completed: {} blocks validated", + progress.blocks_validated); + } else if (coordinator.has_failed()) { + spdlog::error("[parallel_sync] Parallel sync failed: {}", + coordinator.failure_reason().message()); + } else { + spdlog::warn("[parallel_sync] Parallel sync interrupted: {} blocks validated", + progress.blocks_validated); + } + + co_return result; +} + +} // namespace kth::node diff --git a/src/node/src/parallel_sync_v2.cpp b/src/node/src/parallel_sync_v2.cpp new file mode 100644 index 00000000..cd7e46a7 --- /dev/null +++ b/src/node/src/parallel_sync_v2.cpp @@ -0,0 +1,382 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace kth::node { + +namespace { + +// ============================================================================= +// Peer Download Loop (Lock-Free) +// ============================================================================= + +::asio::awaitable peer_download_loop_v2( + block_download_coordinator_v2& coordinator, + network::peer_session::ptr peer, + parallel_download_config_v2 config) // Pass by value to ensure lifetime +{ + spdlog::info("[parallel_sync_v2] Download loop ENTERING for peer [{}], coordinator at {}", + peer->authority(), static_cast(&coordinator)); + + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync_v2] Download loop got executor for peer [{}], coordinator at {}", + peer->authority(), static_cast(&coordinator)); + + coordinator.peer_started(); + spdlog::info("[parallel_sync_v2] Download loop STARTED for peer [{}] (active peers: {})", + peer->authority(), coordinator.get_progress().active_peers); + + // RAII guard to decrement peer count on exit + struct peer_guard { + block_download_coordinator_v2& coord; + std::string addr; + ~peer_guard() { + coord.peer_stopped(); + spdlog::info("[parallel_sync_v2] Download loop ENDED for peer [{}] (active peers: {})", + addr, coord.get_progress().active_peers); + } + } guard{coordinator, peer->authority().to_string()}; + + while (!coordinator.is_complete() && !coordinator.has_failed() && !peer->stopped()) { + // Claim a chunk (lock-free!) + auto chunk_opt = coordinator.claim_chunk(); + + if (!chunk_opt) { + // No chunks available - wait a bit and retry + spdlog::debug("[parallel_sync_v2] Peer [{}] - no chunks available, waiting...", + peer->authority()); + ::asio::steady_timer timer(executor); + timer.expires_after(std::chrono::milliseconds(100)); + co_await timer.async_wait(::asio::use_awaitable); + continue; + } + + uint32_t chunk_id = *chunk_opt; + auto [block_start, block_end] = coordinator.chunk_range(chunk_id); + + spdlog::debug("[parallel_sync_v2] Peer [{}] claimed chunk {} (blocks {}-{})", + peer->authority(), chunk_id, block_start, block_end); + + // Build block request list + std::vector> blocks; + for (uint32_t h = block_start; h <= block_end; ++h) { + auto hash = coordinator.get_block_hash(h); + if (hash == null_hash) { + spdlog::error("[parallel_sync_v2] No hash for height {}", h); + coordinator.chunk_failed(chunk_id); + continue; + } + blocks.emplace_back(h, hash); + } + + if (blocks.empty()) { + coordinator.chunk_completed(chunk_id); + continue; + } + + // Request blocks from peer + auto batch_result = co_await network::request_blocks_batch( + *peer, blocks, config.stall_timeout); + + if (!batch_result) { + spdlog::warn("[parallel_sync_v2] Failed to get blocks from peer [{}]: {}", + peer->authority(), batch_result.error().message()); + coordinator.chunk_failed(chunk_id); + peer->stop(batch_result.error()); + co_return; + } + + spdlog::debug("[parallel_sync_v2] Peer [{}] received {} blocks for chunk {}", + peer->authority(), batch_result->size(), chunk_id); + + // Report received blocks + for (auto& block_with_h : *batch_result) { + auto block_ptr = std::make_shared( + std::move(block_with_h.block)); + coordinator.block_received(block_with_h.height, block_ptr); + } + + // Mark chunk as completed + coordinator.chunk_completed(chunk_id); + } + // peer_guard destructor will log exit and decrement peer count +} + +// ============================================================================= +// Validation Pipeline +// ============================================================================= + +::asio::awaitable validation_pipeline_v2( + block_download_coordinator_v2& coordinator, + blockchain::block_chain& chain) +{ + spdlog::debug("[parallel_sync_v2] Starting validation pipeline"); + + while (true) { + auto block_opt = co_await coordinator.next_block_to_validate(); + + if (!block_opt) { + break; + } + + auto const& [height, block] = *block_opt; + + spdlog::trace("[parallel_sync_v2] Validating block at height {}", height); + + auto result = co_await chain.organize(block, /*headers_pre_validated=*/true); + + coordinator.validation_complete(height, result); + + if (result != error::success) { + spdlog::error("[parallel_sync_v2] Block validation failed at height {}: {}", + height, result.message()); + break; + } + + // Log progress periodically + if (height % 1000 == 0) { + auto progress = coordinator.get_progress(); + auto now = std::chrono::steady_clock::now(); + auto elapsed_secs = std::chrono::duration_cast( + now - progress.start_time).count(); + + double blocks_per_sec = elapsed_secs > 0 + ? static_cast(progress.blocks_validated) / static_cast(elapsed_secs) + : 0.0; + + uint32_t total_blocks = progress.target_height - progress.start_height + 1; + uint32_t remaining = total_blocks - progress.blocks_validated; + uint32_t eta_secs = blocks_per_sec > 0 + ? static_cast(static_cast(remaining) / blocks_per_sec) + : 0; + + uint32_t eta_hours = eta_secs / 3600; + uint32_t eta_mins = (eta_secs % 3600) / 60; + uint32_t eta_s = eta_secs % 60; + + double percent = 100.0 * static_cast(progress.blocks_validated) / + static_cast(total_blocks); + + spdlog::info("[parallel_sync_v2] Height: {} ({:.1f}%) | {:.0f} blk/s | ETA: {:02d}:{:02d}:{:02d} | peers: {} | in-flight: {} | pending: {}", + height, percent, blocks_per_sec, eta_hours, eta_mins, eta_s, + progress.active_peers, progress.chunks_in_progress, progress.blocks_pending); + } + } + + spdlog::debug("[parallel_sync_v2] Validation pipeline completed"); +} + +// ============================================================================= +// Timeout Checker +// ============================================================================= + +::asio::awaitable timeout_checker_v2( + block_download_coordinator_v2& coordinator, + parallel_download_config_v2 const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + spdlog::debug("[parallel_sync_v2] Starting timeout checker"); + + while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped()) { + timer.expires_after(config.timeout_check_interval); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; + } + + coordinator.check_timeouts(); + } + + spdlog::debug("[parallel_sync_v2] Timeout checker completed"); +} + +} // anonymous namespace + +// ============================================================================= +// Main Parallel Sync V2 Function +// ============================================================================= + +::asio::awaitable parallel_block_sync_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config_v2 const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync_v2] Starting parallel block sync from {} to {} ({} blocks)", + start_height, target_height, target_height - start_height + 1); + + // Create coordinator + block_download_coordinator_v2 coordinator( + chain, organizer, start_height, target_height, executor, config); + + spdlog::info("[parallel_sync_v2] Coordinator created at address {}", static_cast(&coordinator)); + + // Get available peers + auto peers = co_await network.peers().all(); + if (peers.empty()) { + spdlog::error("[parallel_sync_v2] No peers available for block download"); + co_return parallel_sync_result_v2{ + .error = error::channel_stopped, + .blocks_downloaded = 0, + .blocks_validated = 0, + .final_height = start_height + }; + } + + spdlog::info("[parallel_sync_v2] Using {} peers for parallel download", peers.size()); + + kth::task_group all_tasks(executor); + + // Spawn download supervisor + all_tasks.spawn([&]() -> ::asio::awaitable { + kth::task_group download_tasks(executor); + + boost::unordered_flat_set active_peers; + + // Start initial peers + for (auto const& peer : peers) { + auto addr = peer->authority().to_string(); + active_peers.insert(addr); + spdlog::info("[parallel_sync_v2] Starting download loop for initial peer [{}]", addr); + download_tasks.spawn(peer_download_loop_v2(coordinator, peer, config)); + } + + // Peer watcher - monitors for new peer connections and adds them to download pool + download_tasks.spawn([&]() -> ::asio::awaitable { + auto exec = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(exec); + + spdlog::info("[parallel_sync_v2] Peer watcher STARTED"); + + while (true) { + // Check exit conditions with logging + if (coordinator.is_complete()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator complete"); + break; + } + if (coordinator.has_failed()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator failed"); + break; + } + if (coordinator.is_stopped()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator stopped"); + break; + } + if (network.stopped()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: network stopped"); + break; + } + + timer.expires_after(std::chrono::seconds(2)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: timer cancelled (ec={})", ec.message()); + break; + } + + auto current_peers = co_await network.peers().all(); + + boost::unordered_flat_set live_addrs; + size_t stopped_count = 0; + for (auto const& peer : current_peers) { + if (!peer->stopped()) { + live_addrs.insert(peer->authority().to_string()); + } else { + ++stopped_count; + } + } + + spdlog::info("[parallel_sync_v2] Peer watcher check: {} total, {} live, {} stopped, {} tracked", + current_peers.size(), live_addrs.size(), stopped_count, active_peers.size()); + + // Remove disconnected peers from tracking + auto removed = erase_if(active_peers, [&live_addrs](auto const& addr) { + return !live_addrs.contains(addr); + }); + if (removed > 0) { + spdlog::info("[parallel_sync_v2] Removed {} disconnected peers from tracking", removed); + } + + // Add new peers + for (auto const& peer : current_peers) { + if (peer->stopped()) continue; + auto addr = peer->authority().to_string(); + auto [it, inserted] = active_peers.insert(addr); + if (inserted) { + spdlog::info("[parallel_sync_v2] Adding new peer [{}] to download pool (tracked: {})", + addr, active_peers.size()); + try { + download_tasks.spawn(peer_download_loop_v2(coordinator, peer, config)); + spdlog::info("[parallel_sync_v2] Spawn completed for peer [{}]", addr); + } catch (std::exception const& e) { + spdlog::error("[parallel_sync_v2] Exception spawning peer [{}]: {}", addr, e.what()); + } + } + } + } + }()); + + co_await download_tasks.join(); + + spdlog::debug("[parallel_sync_v2] All download loops exited, stopping coordinator"); + coordinator.stop(); + }()); + + // Spawn validation pipeline + all_tasks.spawn(validation_pipeline_v2(coordinator, chain)); + + // Spawn timeout checker + all_tasks.spawn(timeout_checker_v2(coordinator, config)); + + // Wait for all tasks + co_await all_tasks.join(); + + // Build result + auto progress = coordinator.get_progress(); + parallel_sync_result_v2 result{ + .error = coordinator.has_failed() ? coordinator.failure_reason() : error::success, + .blocks_downloaded = progress.chunks_completed * static_cast(config.chunk_size), + .blocks_validated = progress.blocks_validated, + .final_height = start_height + progress.blocks_validated - 1 + }; + + if (coordinator.is_complete()) { + spdlog::info("[parallel_sync_v2] Parallel sync completed: {} blocks validated", + progress.blocks_validated); + } else if (coordinator.has_failed()) { + spdlog::error("[parallel_sync_v2] Parallel sync failed: {}", + coordinator.failure_reason().message()); + } else { + spdlog::warn("[parallel_sync_v2] Parallel sync interrupted: {} blocks validated", + progress.blocks_validated); + } + + co_return result; +} + +} // namespace kth::node diff --git a/src/node/src/parser.cpp b/src/node/src/parser.cpp index 70f250f8..f50911f7 100644 --- a/src/node/src/parser.cpp +++ b/src/node/src/parser.cpp @@ -95,8 +95,8 @@ void parser::set_default_configuration() { // Logs will slow things if not rotated. configured.network.rotation_size = 10000000; - // With block-first sync the count should be low until complete. - configured.network.outbound_connections = 2; + // Headers-first sync allows parallel block downloads from multiple peers. + configured.network.outbound_connections = 8; // A node allows 1000 host names by default. configured.network.host_pool_capacity = 1000; diff --git a/tui_screenshot.png b/tui_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..cdefa169ed42cc29283e5062aa5ef616bb41fcd5 GIT binary patch literal 1232582 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%0A)MV@E7;M-<5kHP<)ZqGUn7s`AAag9n{bmg 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

23+R!HZAc6UrgF@%%FskNR@qO<=kF{DOpnO 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

ff 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�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%0DdYP@83QqhscHhG-%IW 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 z zQ27h@v>cN$PK;$NQu&_a9+8#29tpJJ6gWmSpAziVk<3#vkj+-^} z2?~)8JAB}oVI3kiRl6iCiIFV09AeA=v6SoOwWi<4Uk+C)m!3J07YkN8^{G-C3oOb^ z2X92`!WW%WWu9Ye?8qN|X?1gE+~Sj9S;V)q0bKO>TlRZ3?z(bzX{(>yTnTxRl{yMQ z0yN!X2bjWwP75kA{-|>PY(IYlK!*hMBn2$_ffrF3=5zK;@1>?jTJJSmrRHX4=E}MA zqiowLdNM-U;<|{-HpM>JJYkb}MjngI?lgk7=1G{Ew?~HqpNnQCM9cA~U;iWAm=b>u z^LlGJGyuFV^DD)pJ5c(2#z$X}Jf-GaK;gMj(eq#8DHZ5>3I_ky-X7-1g{VL(zW%E$ z%6?JgT$@W{@-M}<(1lGyUDm?(V?lH{97ORbrWdH-@8f{gHcZ zhcf9s&ov1#m!_=w0(?ZELL9s{^sP?$?HV-x2)y+4;sW64h)(M;$Ob?C9%CMW6=Kn` z=3`MM^_%Epz_xmWs}6c^7!%idlA{C7KGzk^9`qir5MdbB22Qn3{Ep7n4g@7PCu@k&M|Z%bim9; z*TnGmGw|(UgVO2qdX{!mI7Mc{Q05{3!FX;?P6iAj56zsNeE?Hl#Q>rfUVY@ zzBUYqJG)e7__m7_!je-_h@G8_IQLoqJX~QXbWjD!hAU1zK~(EE1HRIa3A65^u!V5& zbyV=C@mz2aPN<5IqlJZ z#CEfIbeR=GNb(psC4zMjIK$&_oYLPi`~bI~U9r^0znT3QSpz~A`g+^W&hGFgD zZraJOWYrFt+g`X@zsG0+t32l!_HAG!*>5>a52+7duNHeKvUlzo?Nv`eRzBzc{~x=b zKi)Kd?0)ot3p2+y0yN|-j<@!b+lidf2Qy}lgMJd@Q$q?6?ct8mABn!0t#!$xR8TnD zKt3P0V*O-aZ?q%xn`+z>`CqelrqvaoAEYTxe;W8*_Xg(lblP;Wk)bWy0IqoqPO0`5MPz)P9JM-SLP)%kgxc+zSiATaa6#|sR$K?pj4#f^PE=kmf5Da?{)^F znd4DMSzcle|ElDs2Rg&?;8fcYf(i?@Ua72%^JbMu3{N=QCY7^{b<-zLZU?RA4xGm z1fj0rH8pnSSKEIU)N)(zCdR_LXZ$pMpLJ4=eh1Oz27Ti%o!fPWM3$ZGZcHZwtiSuO z)*rbR-+e{pv!bH746_*Q_FX=*NVr|#w3k8sj_ zZARUW2L|6d(9j@hMH5}7KYRsu`LcA9Tb0)GlP>O_Q+?dP_-eTqfo zT(YIqe9yZ5-adab@buMAPO|LbtL~1(%#yakn8jp;euvW2c*R{;GV}ym0eqY44#yyy zWES(7glo;`)8bIa?$ct|A*Jn^ckBimv0lp=|A}muU4T^e4Jh$QCD`ip5R1@L*KH~(>^FtSnuF!*EO@aL;ieA~NeS9pKomO~7HT|ir|dGpz*44v`B99h@GNc)&} z$ac~N#J&zc3}E7`dK__d=uVY|iT!`bXDOJ$h z7+YUB#eTBmj!-4w2>3KCP$d83ocPTMG#;zOm$K7dzt^VfxAQnU$5Es0nUU^K^59Zx zo+ILf9~EzLjFZ_NmQ5NUOmT*)(Q>#fMW(Y9>|Sm8U>hZgaVWIf@R~chphj0f2aalb z=Jq0P%bbx@@zalu#+~C={a%}s%A47xhAY?a%xO{OC~`1n zlj1sg{V!IikO}=rh;ib8Ap*8wH$&<98@FUeqHZIOlZY5 z7v$oC(C!kdXkE3Kca3k{m{+2=XFZr&iTQFU4@Bj8xGWlUe679E=&r!dVru*of zl~h~F8P9WBkVd_rxkd7i7aJrb*~ceG`v^>iZ$U;6g3wSgY9Q}3heGEmaE&oY5QNM? z_ijH){HKrn%jeI0F;z-_ZIdb6F#8BK_KuTbELDO))NIEhrCC-=MU!qlh*KfCDppQp z45d}Fn;5D*J+K)Kx3-kq+%$?g?{_*9Shtz0%;;1l?;YnfBKAB^;AtK@i-aeMU(|!s z`d9qb7a};p{g-A#<^0HDHFkw#)=|B(fyB^OIE0(7tZXPv)))S`S~djI~krd`i{NXa9B6Ik-Pra2LLSK2NrUV)xe(^{Ng+O z>)C9t?*7ipk_!t+0FCoIzw0z9*%tCe%rQ&kXy#2kLWW zFJ4Wju*LXjoDX$(Ta&ECGA}qS(bS#`mIBh{_lZVE^#*2fUVz=5eHEZFP^+jzDkZ~l zu?v2@Wdm!egByEOH$-vv3eb?6bZ|lk5`TTVoPhG~8Tq8d?zeZlo3TZQQYuYoX+^7| zEQWTiLBuJ+G(Rm~4F*m*?h&VFk3L8bx}J(HZWYf6U!{W+k{WJ~SX&*Mq*X>aU~Xyk zzJ(e+84Edc^`>0@_6&Z2`Izbchvc+&fz10y??b3r@*$Be9N^#d358UPCrpsL``Swgctew>Vc4 z+ZA~jtryh5{k$JZYrfm%f)C=8V|CftcbEGyc+%e~c&e^A%S6@#j!wOucpG!Mp6Pq! zhias17SVSL$YAbn=PZO(V+u^XL`_Iu$)0~D?>oxyx@VPJ<$VCHCUN;SRV;)X>AlD4 z#2I?cKMd@zPAFyaTkQufNJ<_lkkz0<8n|(2Ckk!)~8j4y`4>2TjFN(4(>ilT} zEFbSAC3ls_n>sy_Kpw#=ebb4H*Y2OWk2e@d9Z(=W++Mk+QUy;{p}NH*qvGk?-NZEC z`SaYDg`3UfOKvg!C4l{3odcLMc$vg;eslikkvnFU%r{%pVs;Z(apV`^ ze)xk%I#%iIr}W<~_p{2I!#7Muj6jhf!KkMjnYILzqQ{FMr>N=m%!ZkgFB^(o5u_>o zoF}0&`cH$K@tQraVF{P44t|ZHZ3g}y@s`m_S7WD$Z56{I0UjqFEHk~}s&QM+q^i>xhFawrQsD`B|C-TfM|DtO7` z=Y}asf9B(sW5i1{IwmjS;#CScSvcw+G2s8rv%tE2fKkKU~d6J2y_8pj0L}gKh zcfy0`7gN4IBw=pM+zHZVH%R;MR`}l%_ut?4>!-?VA>f&ZWv?{jLa&rYC6cC8R5gMF z&TTvE#<#i&;0c_R=H`i|t!*sesiy~tIZr42KGDR;bPw%jTgbH^N##P9WQfgMY4)7z)w!o z6JfaTS=eedgcM_9=4-}+Oyp}mwzWP=-#Dk&-K^ZeMO_85y^*ok+;_wp>sSYRF-U2M%)-nxFxZ2+9oV!SAmRuJ3=M!rmLGRAJ@$zr!S%@Sle zthqyl@#2(&{m|oRwW=D_3OFQ8MSiX4lKW8`rFe!_j`a<7*IS|2lo4_^{j9znVn}OQ z4krP6TDWR^867{hrOXhk(xf^j6*roLx z@0JsS&S_Aw)MWC_73^{PZS`mjvwEf_vK<+dxwG!DOdrDuJc!lQo#ihYn$K0CY_dkL zi|kfjKx&My?@&j^v9<}wUdVYFTog4ZfkuMd|?8^W^(R<|uz;s=1@2cLJU9S@c4?(k6(f^ywNC>BXyZ)mh z0P2nY=|$z?@b}1E=~~sD({zsVV7GP%fizy6Ev>n-8%?&W36EFk>aiDQI@na&>1|pI zk1eD0?&*PAVL6QfJW?Wmq5Q5D_E&tYBFL<(PsE}Oo`$YWfz(7OG^D33y%@GNCon42 zD1jbL#EDw%Ydyl6(7rsS*=6LlV=}N{E`TAd-jQ-Wh!Y5UaxGbWL0(FEr}Cnu9)}j0 z&*0d-9)9~*)&9x#vsN&0L4OnDkcmA0_C;1s4{i$eKrUMY64k4{@?!&r5zLD;2G5*^^YI0@dBL=9u78djat` zw$@@g?%-z{9Qzbhcj-8R&$D;fO>tlhtpaFSIB}KH&O6nyQ6A~36vsuVuJ>`QGoOSn z@kd@Kw>oxnJcTQG2be8x+o4a{=L2qa_p|fZpdfe8-t{dMjjWcM}M}5p5~u zKkNhxbZok|Bg@Uq%I zQ?^H4xbYEKgeSZfpLnPU%2_Nbg=;~Y+*sR>GnSP`E2ATZo&?g5ef+^+z>(Hbl{H2y zDQ`{s>|>n8ci7F{We%}sah!5JP>PUQ?H5tm^;qeZJN3bsyuxfA8DooLQBInn5cfFz z=&FVJPEQYIxs&9o5ao7}nh>$BBUsq2$Ysr~wSYv+mKGj^p%E$tE^Iv>&)vzF8pON5 zauGjkiMEEq7104Qb3hqS54+YddItp*Fs+_~KQ)8u{x`e#1C zowh#D!uBJ2!Jv;e`7Xl);aSBhs`_%HO(aSo7r9_p;l>^ULb>2rPPF+ApPQ&I8Ux#McSQh ztT*7QY9>Aa;?ma)x6#kGtC3ne2w5nRz_qrX4IBdQzSg6{3dt*h`HNs`@h5 ze1duHj>&>`+n)tC&g!!O`}xCnYB*gm**HC7zhzygd6S(Sb2D&3vj;$EZZzsYUo0oG zoEuqsVK-5Lh?#9yGFOxB;>DdC5co)nJlHFZcHVG|5=QRX0Y=RW0CX_50zF!g9_|)9 zm=&mB{`S39UJ7WGbl=*&@qW>c6IUMX95XwA)o;%RxYL0eW;KyO)uny8lR(~0q7|4b zx5t9Jat*Ed?ZLV6AaZ@rG{-fopbH78uGOXRqc~Q+d-e9!;ZzAq95|zUVfgt}*_D#m z=>&B3IaOFod^^S|)tBpK<-3uaLF@r`v#zhXAjsZuv?~+Hoyc@qn5&>%J}`LTL&cGc zm71n%QJ>2z3yU+i?K2EV>xJeD@0(TCCqUH~a4KDCq&`< zxfgs6j=2h4J=}9se2(I<%cY+p_pphw$2~Wdu8#Ea`CJ$`DC^_1xRzH5vD%NPd#q)3 zY~!>i3l|c3CF~j3iJ1#lbH2b0-FtUw-@cmDZ`@vk)`91>MH)I*;w8s9%Dq|pm=^WB ztwQ^nY)tp9TXM#Us~ii8nvSQ6ne0a z7|fc4`**hH5XEILvUNV}n?qRPJ_*-s$zHeesC8NV^%!Isg=Aa)g*cEDW8bZziUl|9 z+?Y0T(lqq68=*6wD+py%|6LND;h+Bn1Qz3BGyt(>DG5LD_a-^V?oJ)foM6S?cm*!9 z!y4x#c`UYWmFRPhqgd&MnlzpJ7RTatWm@|Di!Z4tW4zLUK<_Isa0A zagQKm(7wEb8yXP^4oCwEKTY%aL1Ney;qeNW$6l*kv9IiCgCLK#;(}r;_R@^< z$=&0uv9(?0E8tL30!Q>hDA?zG-FR>;!q}TN&hoC|L7LF|O|sbWSvsoFZ>7(rCXLKV z2rG`}$8CM`lcUhxok~bKo@)s1dPVQ(ef+g)sgYL27^T)*gN$k~R7<%U(#efmt7I;Q znaifIi@a)9MMb@%HYR81<`_wZE?#FS$LE<$=Ebt_?7$Mj@V6%&Swrn~1O=YxOea-qtI zP|Hu|1<0Lq+-g@jgV?&31$}rL(yvQjSm^_74EX$_I9CKbjqziBG1d#YhBCLhIq&Q( zNH?T&w<{7HCA1+l>|x~R_#PCvZr^bF$k^LQ)^-cF)zcn|R;HR5eVKH`Nv!E+6l6dr zj@wF4thR|spG_1d_OHP>IxR+HmQ5C0?K~F zt)$HtRP1BSloy-mCK}?yp2Iq}bWY|X)AT@)7z+uB0%iQ#trU6W(P*$3+uHE=%i+%K z?Ww5V{v7|XA^5>?y!IkzFOWT}o#^P0(YMKR>H6XFxCd83OgJN!GLvtln7tDaP<~y% zmuzGaJ|Od;;<(EVinkQ<&Nvg%d(Z~zB^yxNq0dIv8b;uPU(DsDq_VvEM;;aHp+O~M_46)r%Y_DO+Mv!+tNX5U`p4@vLN!p6lzcIOKCWG6U_3r5)GG-)5} zTxQ#et#B$yo_333>tY?~haOb51)}1eZiR@k^}bbs)i_iaLkQPvj|cA7WpJ^V)GCe| zXcaLWyQq=$Gm;7d*A*iSqi2MoqXk^7TEtiN1xorz>dpclw@AFs2kM+6@y9OagD|GL2aZ{FI8(k;Ag!Pa1+^l z`eX7#^iZ``_ZuH~Tl6dtciPoj99K#y^t@E8*T%v2gsG1o1wYMhZk&2=Ug7s@>#gC5 z9E;jmk>zwW;;y>(=A{Z>JBzHFwJD)_Wz`@+xX+q2gR6D_$Fu^MQTpUN_pQsq?@q8; zlJX^rxRx6+y?f1oB7^S0HE#~KA9yUaLw z2pbKi6}Ov+9AXu5Uu#CgMz4H1bd%e)R+9r9hC_!OHxq_feQ!?iq80tU4A2Pnp@p~gqleLUPx!s z4H;opKN8A!C*cO7g{fa`Cm|7IVZ+kX+AgLc7{S%>eoI~dF{RH+k6M*(w_ufr1DE!C z$X5d&8-~`iXD}ZS)XQIjKB2;|2sdvp14B%rp}_T^=)+l+t7Cv;o&%NcT(9bNCXJH= zcJ&iVRy$^f8{iaCq&yZU8}02)3*tk`0JUI4d2v&^>MtD{c)cX;xi_#O*s|xwB+Ct9 z%9-L~%{_XB>odtd?s`V@0#g{`gULo06p!aqEQl^}!S(cW&y82QlQ(X_DJg46`k}mn z=E?u#Nd*wrmGeJ$cPc#H4^7IIH^LBpsDXej=uA8zTkr;OjhEmQaidmgBQW9Ka_#pV z*MNOikrVu^61TVA3{<|W=kC^sjc|*{ZMFWp?B~R(t&Z3BjUrJ_;aJRrdS5{siLJmR?W5-1Y4&XBIho$cJ<`- zUsj5hJ-XR@%Mb(bL&I6jO0Q z)~6XbLr?hEZVTxq{e|zIXU6C$E%Gmfjg4qb<4lEQ*>`smElt#)Q0@7h^+Zqp!?Jy& z?(g|ng^b043??cw-+4||`OjfdNqXp^La~;qQOOE5kdMq@ro^57y}dV_N{+EApR;ga zqo?*I7H?=iD3PjLqytrBv#a*TWV4uH)&F7cy~E*b+kIg{B9br((aWe2y+m{~5}hE0 z5WR~aYIKH>=)ISiBx*!2Q8RjPLG&^hoft+LW-#CVyle0Mt#|Ebz3=*S|Ht8QINbM~ z*L9x1b}}OrH7APXFQ+-}PfA{$wJjko$i^2h@ZUup`3dpYU4R!&ZeU`M-CMvux%vgB zR`K)xzaL@W&+MjHq-KQR(9v=N(F+Yuvqb&Cl|w4Oj!XhBD-3q4V=FbC|BVv`hKpjrzSS zq^W`?iH&woqSPA4hE1As-~USRV=Fe32*ocW4hJ}_(SHxT{{JWT{z!CdChA!*x9P}B z0N`1lW;zJ`{@tyKR*I0dbwJ1tH~|?5=6mIN zE@z^ab$TI-CeWy8XyD>V%;kapYZP)%5pihSwdL-~3cc#UzTc@ReU=oxF zH*)2DX?Weo5zs`$ik7ZxT*5qxi8ZywBPJY+>#gqsEwsW!gs8>X-=kTGN1snfKrBVA zm>sjOq$oA>Z_UI5OM#n~6On87+sV9J{S*8RnEsNCg#*CtTpAa8m+FNEqm0LE-?jXW z7yA18vtXM0ti}~=1%6}sYJq2`;}rQtcq~0}$43fHYL0`~?V$(u{j2Ksn7qEN_O6>- z;}ltYm1@o(6^S(^X#`e$2gwCmT!@Ki4Auv87!Ex00}`66ya>TrZH;!MjJJEIoVm;= z%8>F2LGSV&t$<+$P3Y(-{BWqa^q%aCds-TF!X{7PB`scPS;DDZ7r*%5fuaA2C=K?b z3D(v#f5j9by6e(1hi{7lIOyOrG>T0)=mNjW6F%)XlAh|cbJTYw=(j2vE18>&b)0A) z&uxiK&9GE|BJ1R|r`x=&hJF1|-=jW?c=V=iJL}%;4VN6h>0dUYz^@`TQ^3(}+FqfyBSLuui)HIkgw z>yaNG04yqaSB40HLQ8P@Cf4F{3skyY&wpUZ;~){-n<%hJc&&&TE4PjtMtML^kVm7F zey%2dHNH&(asV>Bq)D@WJ#ZSoc8Uf5&2JY~Z@4OS&owJ*JJY8>k6(EH_i!;0=*HO# z7-|rze?y_Hm5TPejyc1;@McM%o1X7dF!|Q@#Ev~S=coMvDo*vi2G_0KNQx;6a*`w- z`S=`zTE3-CEwjJ|?oz{AF)O!=?TMmkjQR`z?pPLTa_S^!h@d^kyS@1akM$mS=AgJ; zOzbxMc!3s0mdO?{MQ^oVE!OT)%uyQ)(s?|bKFaw*NA9A*`@j-+PzWCzwd%=wnQVXb zG_KC|D}BAF?C1QMhTeld*#AD0EJvJ+(KCT~cguM)AQrD21pRI6pmw{bAZuuemQ2O0= zvbfXsZ*kAvP4PSjH5sOC5xqxoPlCRvn^ZjgCqC2biQgA0u zHJYAbhc%J9M92h@Jlx|W>v^tZGi+Hwv*xiimhZ9Wk3Tp;Z*2@swm4f9Gza#? zvSitgY-^)>Vl;tNXf=I~w~5rT{$An;ue7~h-YKO&cv%?=Fhl?bt``bC-*Pl&vYV@# zL1QWKu0ziP!f(7d!+WNpjr_1-VnO~F-50iw{$5QhxHX7M2@-z(1&u4!Gha>{^X&Rr z+j8SEOB31!ev5BpZV11++G^pk^eaiov|hXjpXc(r8U3^kD8pa%=vz!Oauf`VUYQ0^ z^|+-{{K&_ctiVcqtfkk#2Q!vT6@##2@&``>+`Vei`3}%&gA2%E@ID}5@Xo-iFgNRQ zHoQ*_IQRXc0)7vQqy5V5rGTl?_`Ot1;=bm8>oEOCaz_D%C_bzrUy1tsfeybP5W6cu zkJ1!}}e9n8vr-If_9lI3SA z*YZo^LHFcfvF>_WnuR$v%#9~ElRlq|l_&AO@)$szcZ_GBTgCazjHlCb^pVJ)rIoB^ zOpzz+tZxp0#ZL1-bn<*7wY)W&da}hC!g?^4`eVz1(uDh)THH&qnyPZCc(eiW&HPW( zo=@M|GUpd5RBv~tx3>ScNAe5k{=RUFk04>;0!gSYdoFMdPlU-RoXV@T>Mn4YDl3S| zg6as%VLf7ZI{VP$lTOHas=0Pxd{P7nK9PJouLf3X@Bc2`5^tm4Y=B)PtLuFuQthW= zSS6KciOEg!-lbytSxu$mve~6Ltw;u1qgZ@6+zNMeF{^cZMXURDC{NAM0O9DWZP?3{ z-|^OI!=u#V5T9CVrkc-?qxj?AiV5SviAo}6oS*kE5({^==x}W77e$~0`&ktMc^;3dgX6Yq}f3)^xI~&ZCp_rosjL@kODw zHh-G%z!V`i{DTI^;rg(89HhC3R;dHmfKUtMWG^$xq^FT#g`Fp4-+EDICKUpW5N+~A z_f5ILJRPuMYyS2q{7cPF6kg@=Z#9JT%%dSe(L8t-hlqJHkS5eOCEOUZ z0Y^{%C~r|eTp#M2at=*E(~;rTTQg@CKBWrzln57PZL}Ce>yxgJ3vEFnU@oZa-{_CgA+zWe^v(NoMJhUUSIPKry347#=MXV7kEn1 ztiNsT|4FAbKLGT|hbqg#8P58Q>*h$X{#rA8@ESJ2bEXiMTRxISi+f`s$&?%NWM*t* z>D>)?Uum8U^9gq<@8!r_T(X<$w5F&>%+1q6R!%i-^bFz5WL?B&CmB3Hp3}DMFRQ20 zju~8bO&QZ}Cs|R-o<7eW9m+FEpJJ9%^WEm3l$$wa&sRZobE)5N3+*J2u2u+l-D)-# zcN@!B*2awvNyLYBs*=4IzMatlb=T$nvSywmD(Ik~dI{*F8=Iw*VE0I`V~!GXQ(!Ay zLjIJv!HLDzh3H_(q`^K)Uyfb-g~ajZm1MKYU^z0~{uGB~V=X@JT?7k22X;(Xy~{dH z0iLFK!t1e%m)s}Tt7(lEeJw_RJ62$ciO*d~=O!daN>0#wNEPCnbBjnHEILKVy#hAU zvOoWz@{W(Su6aXh((@eH`j)uwV3EhMMl|$tHFa7o@pERs4m3wAtL0P-xHk1yc-22s z>sU?xBv@!i*DJGMJC2!=tBl~`JNrV}l=yB1cgVH8})(>nVJj$qaVr)bjRicUH)NtJ|eRrONi>-D}_@ z6-*JXf{%*GfN)6?_U1r^k!g_euE2<%)eqPltQpl4HxSh4B8cUy(UdTs&62~mhsD2gi_AWf|(dH5t4P%b)N`&zh#SH>3 zX2*4Sc#Th#x;th>TKlIfal^d?GFYM%?z{QHsa0How7V_$k(6p$xpAz+=^Jw~u9(O- za-1_2;QDK~80JP=&c!}Sk2gkAk_!k!2mvYz6m$ zRv?{D%1b#vYI%n8y9l<;mjSksKqN7**YN$Pox^Xd(u&Ka7 zJ>l~a1kP}>JT6qLIOU@fC_70CS83))nbO#9BkRIY_(_@#w4v_F*;b+Z9Y38+W_3YD zl-$(UHN2;Q6Twy$_NCkFjndaQ6Pu#CLgb)3E;{~Uu*iOXpl6OD&8`m&(RvQXeoc7x ziY&vV>7*c-${0O#dzChT z_On8Mx$Bb&I^FGdGE%i4qckA=bkM5)kE@LC+nO(NjGAy-Xg2+oZ~-#^WBWBSrtNVt zvJ{EmJd|oOj03Et=XPzU3Mz-ws%eUWmpWV(@x5aiq^Z{nx1(h>o*k@Iy=nRvY#xcc zM3HmJ>7(TxU32m#bThtA;|u*RNw5Cb{?1?1%}=hTf*?3?!NBuTafiv0^V@4lI+99V zk($S+rhx|y;sO$rXs8R@pM@sq&y#-51h(hjy${-Y;6LVdwJnu7<(oIZ6g?G@lz{dW zoGONq>6Kc%Nw_`cp3B2i7EfB~zLDdx+Zo|qF<_OYAbFm6U&L>6kWpB|4R+qwJPKFg<$5jINW<(1ASTb+IQ|h}7 zl=eNbpQN9uih|-o-)FcYSba{v2qZ}!kul18p@(U>#H#zqXygjCvNE;dkR-{m7gzJR z_;loOy^8k6X78`0ut_*hCzq+}g?nxt^suT|+l^2js9m21BZC9TX7zq*3H8VZ7|H;h z^ME%v!drcFIkU;*?73l!t9x0XM^+`}gKcuF{V@qzcRh`?IB zHkeWog>V<#lRYru$j}kpK|J8!ldaXeN(ry&4#p497Uo2+!oT>$_|>DCr3~r{AG)!= z6fmR0e)=N)Z9lCUeg9tFKUM4BezRvodTOD(_`$LGG>pap-i{j*`dKB(~8iMMYC?jTHl0=ZY^< zONwjhKBuQVkoDh%DcT+nT52eC8f&&Y(m=cX*M=UDiB2+0-@xd=YhTCGa%^;6UbHZ*>B(6ad5G^&S~M> zi+ergg!1qn_Jbvk%fi|24LEGVBlo;0fpgq_q-;o?)#TuOHLBET90bjNGnYoHUX%`X zHZ_H&+}+Ewymjdlq$Jk9VOA51ow1u-=em-E^`Fscjsn93h9ZYB=Dla9nD3=Gus>2M zj&E9W%3Xq3q?wtvvGe!F?XRUss*GLN9t8|cr*uhPyQ|v$XOpF^fA@BCR%hxU?9>DCv)790^N|5-D z@w3a;S;RaeeO)~?z8+)EWqySOIV5NXTRbX07Ux>g%oIQtu-F*yJvOcSQJPAet-F_PV1N#{dZRT=yZ}_59TN8G{9~bW ztWSbtH5#rV(A$=q!h9lK5yITbOy+j`aBMW&GDUu!hChIE$UzN+* zYa*DL%WrI)ehvdF=j~G)?|a`zZ2iPh+A^BuDv^Rz*z2oYg3fMN#WB-LA4vlLXgO<< zs)jaLg`!5`q{yHBsCZa+ZDyyGM#`8$A_J{W&Bc%tX>E=a8CDeh%H z`xIYAUO%~JaHBL3< z1B*|f=eZ1FWx9TFeH{xqmC}FjeQ;(s-g}1=bKX4!FRb1err3NzTpJp1`1oqdRZsNd z_itC`43)1-*kac;?qxyn947THU-B1cC%%uL9#|bxfBPis^$!-2ckazff^yW@`I$TB zC|EW;P2;-Uot=n&ekQW;v|>IKPxOFJk!NQ&wnH^moMLBUPU~U~GpeIjs z4pBh zqTF($A1O&?u#)5QXZE-gTiRk>JL{80Th=u8;c&x!E#1}?V9X( zW&3AC*9jXVpLCe6H3lBmN(dtCOk6K0jf3-NELn#m?B=~1S8!newL(4qG#dg#*a##J zZ@t6SQP{>lOn!5|(odgbIgjDz-IRJ2C2k?o!+=8Nc2MIP;;@tY)rkr^=I9a+MjqoS zUH=E=H4nO85`%4)gOxY#6QScOjgIkq!6JfycQFj`EY0w2uKw zjvC>wB8jzM)=aImt^jOVZE4`MLK{HL8 zFe$n1E4w#FZ`MNl#Qw?+lPe4hxMuIfgyy4K@2)UdYoc>)RS2`(5e>C_ydf@<$uItB zS(B1!up>!u@u-@%TP9ujk4P$I=`K)n;(*z2YaDHSHPy;F)aQR$M}f1$vT@riy_63! zC;E3tw~Hi@f@FVMdr=JDyf^_AsvRMKxTGYuWy677k_5{0xxE9ZBqkUEo9A9x>C^FX zh~YUOOEinDg!6NP^+orf(Yg2ecAzd?%In0KGkKdf?d*xM+69`Mhj$JtHwksJka zC^?fi&k~4jsFF;>LvydQkB2>T+R%XZ5kLI44f(d2#D8+@oBVUU?Z)uYf>-S}q_kPU ztWjzxoRl`F`A;74z%pm4(%ibR;iAhWD5hZ9=!*P9*%AeWC=)4${74>bOy zd(__W=xL`c-1~)$?~wsl@}J$Bfw^7elk4oRC}Xa-zY&Bw@)OYl<@TY-HBFRZ6lr44 z&K4RC`>k8^rbm4wGZ zO_9!t&tcxa|6U^43Y8)DL3#>QZDYr3u{{%WESvt~Tovb#)jpb_4hN96Jz_O^Ieg#ZHKD6?5bx~BMbhun`k4EE+zVQ$xQ zJ%U)>rAFVsW?z+3t1)MN)lIDI+g8luC=w?iLu@8f!{Na&&|*#6xVmH&^-_jdS+J^C zVLAzBXw7E0&SuzM#fy*3$fNF4k<{1vk|MaeO2X9J&I#F4S0NXuin!G&7pjFLO!nOn zAk}-#2@2&_G=TU%10G&;Xr9ECVmDPb3?mRc zP6}(J`S=y$RM;UJ}iD#;Mx9<}yVY)&JE(4S0 z0Gj~oJ@yMamw z1LXgXTy~|kHw0LsCHW+uz$FAx$Tys4@$8CY4&}`TemEM@(zw;!!wcOn4D!AnzLzt# zJ}+Q8L6-p1sd~)F`e%W~*LXDx_-HU(}UmWREye~=>e8o&oq^rpuY~#Gx z3MYf2td`$jwO>}eDfXiW_ibf#P#NgI9EE0zTC1Rc7Q8-Z800s901fMal*cIO76BQK z(My(ZzwJXRf%%B9qO*O(B)p%Kgey8GvQsKC|Lbp+ON9UaGSAlb!$p>PjYio1xvReJ zxzz8kE2`g)S8k3J0JO))KRGpfKS5b959=A6ow+J%p7G|#{8b?EXbp}76V!P*vch#~ zN0O?d5l>a&soc(#QgBW47;h~Fp`UnPF)lQLPRg$HbXh_?_~{9EOxf%S*qG2ajeM=} zWeBg$CG(z%552I4*QOi;|LvUgPiW{KHR6T~#ZgI4_$zuJQ;X#}LR~Cjh z<2jl1E<69+ih7RJDmB9jf6r-}*$^53fH}!4wSbxY57s)D2V^=18laiyWDG;LG)} zd{7^6ptZFupy;F%I}QD9r!5+9{k)7s+S`ynK+T~;|Jz79Ng{ZtqlZW0HM@6v5NWEY zNS)(?$_s{fe5kS)p8Ws9vE#9gMoqyk-fXjsrCegB-lddTiX3QXOR<;wZ1;J`k7jAZ zWj-NJ-#EnDs5n}h(q=WH&R)+}Ir+)B8r7+O?e7!7TI)(=h;Ic8s2+#r zR<tMIz%#u{q(z;5mFb?iubouxkNB zs^@y5k`l@HTElpRn&VD%q*|?&l0b%c(^&X&<+Wi~f7P=<3f=s?NN+}``*+@>VX`T5 zZf+9;!meKr6~~6MTGXJQ#DsP!}4zY@J8uYdc7 zLsJo($7ZjSCz<8%y`)3TSvmJG#U4bRo3ZHA;Sa7oS>2hHQBMN)Q{i}#S~%*m$;l6o z{iLZo6ya|Bx2BE%M6drfV`p-Tq+^?h1jRQjB^TxNOz(ebsLPrMq&03X|2yDgWQV8d ziA=&R{}U{KPY^`rcEAZb>3Rr7Dj6tI5SLFWmM?ge{Ni&cRo4fh&|7kDS1P#8@=Yst z8ffxCxZYeq=Szl|4;7t`paCK*N2C6tc#wA)RU(2ZbcNewufZ?kSMAa^}EMZ z4Jg@>i`oA1WFe>KoM-1n^oq6N0J50n@_>8)`?CMuc|*;Yn9!_O2`(KtL%qjrM`5hK zB7)g1Y$%-%A7Zi~&V~uZGdvv2VTVHvIBqKT_2G<9tbVHryDf!bEl2q;FAU2rAm{hC1wv)<5-w&cT-K^voL=&?VuLiB~>f7gSZnXdJnF+0>XbZ;iQnI-3kh%QS~mnw#)%-I`($565T|^fAntx+HxCj;K0c96 zQ3ZfK^0&e7zDKIo?qHX9Tk5bXWtY!yHXhqu;3)3wIg^3FZw2Qq?;*X`M+P=pUVeMy ze6w$EruOiqZt?8-%%8_s!$@hVF4S^3M$2DufL5aF(E{lpV^_k@c!`e-rU)0UB2Q$- z-3KPF$O!aYofiS;M3wsLe{kiflVT8m!X3v4>-b`v-PI&&ueM4Ubiw?2A9ez#} zE-K9M_K2l6&05lDusY66op+O6XKtDf#Dt+<5D*SH#XRDNTpm{`9`08}z;G+7b*v${ z&20tKz`WebU3Q~>bvhpwj7|=5z-j{Zw{lv@iO-`#?|c%o%3qHM)yrxUcm_bce_?dp zs|v&M!G)h)9=C9DuDP$t1@xs%JbQ0a_dzRB^X>!8CU5t1@T>0j+)=>lxRNMGV}P04 z{6{8>+5Ag0vF#y)Yuve)*>tOapG`rC{y%Xn$c2Ak?G`LghzFw8C=GrH6yH!%j?V4* zwzuyjpISIo1}G$AV{Y(li~-1*HV9JBX42@*4)o(MOg_dSt2sqOhX(vC6$zJ8v)oRD zwpo{7LR81f&N#W|`&0(&t7MR{ zYe3Dsb8{?;BTe0hu~TVHf|6Sk`Pq+JzT_B$Q81-WmIaE%M39CrPJ3JiaFOp$*YcbE z?B_%IGM*GxibG0r0>Oy%3#33M5>2OvEsw$+Vj0Bslg@{1iSw;tobL z%}fMvS_*7pU03x50{}mok9>!wrs4W@R(V=_v~>R}2-pAUsjRs7G+mo2Wun$hn*4e^ z;NJyI(`?qu7B|7Y56HlY5b0aG?;pJkyj$&&IbUES0BOr z7OzB~1?agPH~7_he#pFFs0&QVg>;f$+;?A`hm5G(a#gDF-9{C+LOQiVZ!S;3mByeUykA^ar>KqGF%nhPU{9l>CktCt(wV{=*ZOUe;^U`42Rbh7^?oEcq8)uU#IQp znr}U^FP#0Dw*9Ysmm=w*@ogpFQd<*&PtJn*?`z2>e!DscOQ9_rNXDn0o{qDo=hL|d z9-N74l;9yfp*&rk>F`1p$1=E7pg&G1@DU-)*-L{<9@qO-+-ome4&otFT(mo51ZOHr z;;%U3)_a;^UO{6pojyduAz|yx%*Jl*>i85c&rkLE{mJgn4pLeG?LvQVbra#MxMf*d zOK}`Bt!7#tD&o?t%k=68fR;&F_?seQcI3C_Ke%tLbPY%co1fPojK=mt1KlpVV`~2F zICHRX>8Ae70t4DIE&jBrV(%lBhY9b{0n=4)LRO0PE5Zw%Wxf8`zY5MbeZ+b96(QBh zY-5#XhIj4*NJtITbtfp#%2ggFA0BzHmNa$7Ud`Cs5A-zH24>&*Cs1%PgB{6qu(%n8 zJyE)KOUU^40i=cvN+GX8Jizu3Fm6hiCVfRNJAb8{h}`OmlkcCDv|y=WSADJp|D;&B zl&jJG7T@E15r)SNUx(TNh1c4gHO}fho;uJQ?82}0Nvz@J!TlcD{R@k}6;M`o3$1u7~x{`oN6Wa8Wk|xYExZn0J@s zB&8biM|MoRHHa+05IM{prOc2XW;_Nkc(0Cj(UObwlgArxB}rSqGY5gIqDsy=ze^t^ zTLn2KSUzHvHr!nbk?u}x1NpB^`u@6O=G)fqo0$YX&kdtUz>THAfcUFh0cR>^I|ayO zky&s`cS2XaH=~2=^t1Sy?FTyG$KbCYcua6XL`3oDzvwXkm1Dl|wFJH(Bs7`diiG=*^Ty%&U7Pp=znmz909~S~-5^_v;mVDW~CW0Z_S= z+!f8i$o>a=FTsAC1U}n|6ce|K%m3R30#E@iaJCAGONi~b+XU!HCZ#nI?ASdX0WeGy z;rm0y^t#DX=_hxYFokPFBaVhVEVgQFznB1BPmC5pQt~VGXz6{;ej8c!pchivZ6G$Q zPmn~qoV#LhAgdKbArqYM9O5e_O-G|8aSPz7xb(#%La*?3&AVPrHRL8`6`^P(*3_Lf zP*x7#N4{+K;q>te?5*K(=7Rnf&UU0N1Xj59_D#r1*~yU)Oz^k!s1x&O=R9fRAYXOU zbkA*Y)t52qkL5osW&E8gYe&nyi&QCQqOt;__Qsn6Eg;KsZo z62Y0UIT}d|F=(=FBF@cq6-?6$Gu#R%_1XYwi6>vhQy)N44F7HhGYhOOwSPPsH3H2_`o2=7WyDdr zt)zRq_7E923xI(Gx{2)7s5Lh^`KW5}zrYp{>jpYlWFyLfO7nL`IHF>@WUfXwC zN#fCoJTAW;X#C~b3;-lRG$h|{-a$F7B)I5(Z*7O*twNq$_mL~68OmXy;j52bVVtF# z8Z+nZX>wE6E@S($1^h~^_p#cEr^8KfG-)as9!UED2`#UCI(T(|(>EuN9#MW+5R7mJ zbXb}?<$=YX=|T@J5~Zpne}z&rV1|C$ z%vC=W{YF=AbAeh^ya@_Op}BtIFi~fwJ!j4vz?G7cV5>w-%j384>7_Y<1C{}QTZubO z-YNIFj@%7`uFac5;(-!`QqF=P-)OH70xfq3`^loi-9~6n)~W%m^nUXA`@EOXn%{_m z`kN}rr*mB`ijR!>^~Nr2>-uZwQvbtum4r$n{oh#t|4fA};CzYB{_{983ut7p`oo)0?7#%bB(V@dct3f%56rv91#@qfwQBzVM<6!3+bPVCr zxJ-V0W|F)$Tg(70!txHh5>P8{MR{pPJ%=eR-F}o3;LSK7D#jt0PIUJ+(2ViF*-)xr8yX`3$e(7$W*=PE>BOlDjj{J1~=I;Hh2*z^?e z@_9NL9ApEcj(}d&Z}!?uYzs}B-Gs2c|AMx z86hQ6G%}oWwbAhHQ?&5Qb+@kchJXWBpeFmUlzGqLElCu|4OEW}dTH1xSxe^L>y4w~B*gPr)7*5BN{J#7OYP-^Tn3xf!yM#b4|HSA!NOk8#PA_42%2+=~jm znaFZYQ+iRAwePaLh8q3;%zji6)UDVZE~y_qBWjQaHA18Y(WJ6Pxb7m!soqLZ>VDzniJqXE$9?~G zH2=V1JY6*R@C->kwbwd@9s~9${XS3j@iJ~910e%1B*+Q0wAj9@ha2mMuuV2{fsh9D zEiu=!a^jnyHZqMPqeiJc+4&c!#`C3);RP?Xa347Y66jWA<^uF}G15thg@y+v4Q|J@ z+1F%yJyCc$C*SEmjEUNxWN19S^eofxqeu1$^~ost6i;1quZo@O=6`2toQGfcD1Ls! z)913~uT(mcFUJ2Xfy$MW@?=uc2Ao5sym`pMws_mt^2uppusR$tdD6OZCA~&N1Nz1| z!frJ(I4j?UcS_qxH!N6yA|~ZU99Cm>Myde}vK@Ynbz4 zF%Rj+eN3&+*is8Z4=>e-*m9NmiD$^f^h_p2uZj9Gx{TFB8 z7U#ef3(d-SAn?KVubADB6WcKIAD$hN6v7XX_ZqkrMD`xGph! zjcr8~_p`u`A9ZD026H=Or_*wPW>`Yv2wvX>nc(P-Vaf8*eR_Ji3aT3%311~nyyY!) zfSLi1ua6*_Z4fP2$k`9S65mvpBl}v_y|>_pr*5&?TmOh-uZ=-J8_IjC)$9z;AZbiORJNeF*uBp1)+sVWmZy7 zs*mTeS_XK^bYI_7+XZdiQMPN2VSOISk@s8|>NMRq02#Y{)%|&od;o0>k5oj~d^b$v zG%Y4uhKnEv4lu6|Jd3-U1c14O_g>Q*a>tpJv;Ul%YrE_drx}v|a)%V8;{xa!X=-HpLERKmm4}Tf5?rEC0 zbqCj9s)yRAz1fJ-&~tkEm7LkuQ+2ISiouTzFtDv00!^GKpCfkthUBM4^mX^i*1F6Q zc%V$01ng2dJ8T_!=(*pAh~n-l64_2zs0Ebhi6STt#X*7pFE5VmIdIXx=|d zB#(6@*3wc*WH&9qO&Hz=bDPK7p7FVHtfBuYh7b^FKN;)zxO<|tu%dYKi<{@sWo1Y9 zZtIjxIw~HyIoX2|K6~DhtXio3y!ZibtG9tzP+61gC}HAje3(J#>UHfthW)!99@Wt+ ziGqel%V|}S>TaT+juTR#>ulY(WiUD|GyeAao(3Q~;>!tDN>+*2HgP_bcl={)td#aw z$)uOBlt-r^yd$r^+V!aTM~vyu7~WSELvgjzs4`qS~m?InB7-+Zx%iv$<CW6Dri#g&0FljtfOCM8ufGBcaRSH z>~7yRyOB@M86LmJyt}BASiRZgk5`K;4E;K%iZR2TiA4R?7SBI5X2+a8U{}|n#d=pxGjv*R zqy}d~=ja>vi~B1vLxiu+p1T@Iysnh7tHAO6O>bpPaz726=d4f z0z8e{X8sM_iBdvH%fxr?e>_!fV#}tRM_}+0Ko6&(`@vcJCfN8kjVtRQxtcjnOSe-R zP*W7N15GUD%$amTnP^6tZcz`@6zSAO5H>8_$JQT7yjoKSC#}PrqvCd4^^-yqBdAfh zm>VLBVO_^eZWa=M=4og`GmTrOx8mGZ=I0Gpj4u(liirn?tiQPjcYO5Z8$DX!!GBj$ zY<6fscVd&>{Uh+h2lZ$ry<|)yp#l5puNa0jGyk%{iz%04_I|@XaeEa{hm)1v(7tRU zx`h~~z=8!jj>S_}mkalmcbAe%V^g2HjiSck{|;%`9|=-$LV6zK+hmUsexKc+12UNB zTV|-GT5_K&%yKFl9|~|agB|)dH0w;Db@g+FmnZa`g_YLREucQ0!z#dbFSEqXNr+Ae zdz}z+_dDiR&9#_>5LF0qfCmGAT~MW^MGnFcNO?Nhw6)A3c?|bCv%1ws8DMRr*cd$_ zY?I)ue*Hvs&?^12jc%}gG$bHqf+||!QNgWDQQiLJ!|B_7EwtfU!2&F+4|Q&`=jPq% z1{6RaEEIX98jl~^JB<~7$cuwgX=xbszBWD4WH=Lc0^+@LCPN2Xl&_|W zj(X-1-@IAWSo5Or?Y~Gzi{}T1oL~S;&|}0na|VCV+5)g}ti~TIVbHzVGaJ@Koq{Ks z$w{P$Q%g;mfc3%8mKh=z{)YJ9Nv}4>QU3Bf-ZhGJ3ZFp*o?}rbq<$q#kD!=7?*qc$kni?YZ&L|5N^KPy1 zMP^J;p;ksBYk2Lx=7n8gq__Hs1-s~;1LoTC-0gicVyg=Eq zJJFxgJyX#!`yMMqER_p-+vC??(MlN)3f&(jIZS!)`C&q(OgU|gnxM9M6FZm9nRxLwe;d1gXmP2@7tqQcjInN%jptkbbUD1kP%|(jo9;j ze0ez1@F_rmw&YAUR8-_j4SU|N_|fC?NtyD$`>c9Kh6LRG|m*Y^8HJM;g2|# z@;Gf$o1b1NS1lea3B*K%La?Rv#^azu?Jn$&?jo@80i^d?Z7g$CUf#NKtX8ULNAfM@ zxw8&y`>Q{fw+~bZ{<0BFTos+t9Rvk(tH!{Cjx$-;_d8g;Q5n+5-L{Zj5nqNBwK~Mc zDWzTVRk&zrML%43<}+KG)t7*Q@5zgZ0()rQ;S>?*{WZ#9NW{e*XK9pR`^? zC;%RIyFtB{w7uko;HSX&=l$&vh*Cz4aC%^_{T>TD!cZ}&RdE%r_Ur{XeH&noJ5Bf? zY_ckC9nyo1IczH)_%19TGulB`s#e*{Dot$jq&HRUDB_t|X5j}idx|4&o!!JQYeDIS zI#IVSw-l$7n5_;fb>NDJRd-5^&L1E?_Y<^T&^*L4?;orv%Y&hp{Lu4x>53M zW*LygUi-~^wL6;OQ%-=blVe$2XD|?f= zC~FkyhnJ+|ipf6A_M|^6V-Qgi^ykQ_GQV=Y=A`jrwfR=UnY$AgkWP5~pt?n#q*F6= z;el;l7@gn~UCwV^^p7Sa>#02ih-e+cM+TlrTMhhh9-FDQd)D$@+;O_%=r=Y0c>Q#V zjzH-!0Z0HrWi}?T2AqD0Cd4lIak8(tj2nC_+CR!Hd}{<%7c()D%lTdkSNi5;=B)FV zYx8hpr2Gt&0T68BJdxrL7hCgg^a5RiGSy)G+%Rkie8V+oWQxyJT=O-@V(lID<}*&` zS1=u&KaAf$<=>6qgHEn|8mDuHl*(^)#BnaFu{9WpKP+x7F|On=GtxDb0Y@m07f$eX zbUxpif;C*Cb#k5<)j5HpPw!!MYPY3yvoaFPjY?Z4uxLURR%p=Ebi-m1l6))S=z|-l zthKdftTlJ3&Drxb1tXq6x<}FJcaEtoHJZ=)h!eB>pd#X53*XP$_h=Ex?8P7DyIS)6 zu%Y(cHIPgq`dr%@(X53Oj5>AY_+`Hp5ME6i}R5FOlbJftb$ zE`;iBXkjh>1a`MB`#E7uNL!lgLx3FKad|$7cAV8B_eLaGEdC6ij%Y(lWr~Gby>$$K z_)1oi_4R4e_-OWI23CHa)=cF*rVt_>V-ZVHDU?g+d2t{L%9TDrErj`^=u1a>5&K=v zWm={}9&*8JA`}ApaAvO`m%=4sX1=}+-()XtI#g)<*T=y|jHV|J!>xq(Kn{AndzN0i zA4HiM9-FpgU0iOzhAdYII=?xGrU?t{G@rheaR2`(d-JF!&+U6$g#uO~AXa7~VntgE zM8+^ADizu)ptY5t$P^WonII4diGVW5kXl-q0uiaA6@iEdkx_vJBm)QpWQIV(96}Nj zAPL{s-e2$it!wXRwg0gIUF3PsbI#uT>~r2L4my*#HExsLq)T$RuNb$vvbpvsOcw!L zeoZ`|uWmb1Z+Up<*u%U;QA|zpdVR1HScM&}dpzWZd7MM{C5d1vtJ5Q-r}@oR5&!EQ zb7SR3x00s7(ph5E+0HoAg=^%5?%LpC zIvQiA;=ZRg)Qg9;33Um+&Dm1)i=Y`V8{oK5Q^&e*y7_cXkF6DUU*(Hmjgt5&&YI0k zDNQ-YJvSgz;28M+gOTQR}Ca=6O{%ctCfuoGMyc42;1b&KU5=|ajTpHn)zi8VKa zbTS7d#j!UWwocCVHJvYtd>;JVb`Y~r0n5%jQ+7?tok>5#WLy4sqvv zGG%f;?))U04qFu2^gM9@UL;dp(hne-Y>e~Brf+hgTKP=_=Qcc!8bLm&5gy!qhB%l zLwaJSv1nP-+Bsc>WNat~SWWO!^)N2#-Ja-IBTSyi+^nkfY@a#P5@<%*|SUA$8hOP(MD4rk62(`S&uj2W>CmyHVb^f zsy{ME9`bwx$e0Bk@@A%ZNR%N zblqX5kr}8mlz%Q0Ce;0@$D#KPh-A99o6WC*8ADhBZe{$eDnlRP20HnA2Xg1U-lb8R zYVv$~_8kOG1AN)^w~@?=7F9M=<#1^1YBk5)tg#jK#HL7N;!&E*GIHs>K{bIL8t=^V zV!iHn=nV^%>|JUhWGyM<*u%=Ihd7WX*Do@riWVsoorF%pl7gPQFF7>hDLi3%qB}g= z^1Jeps}Uhn(@8I@?bm#N`ZzDT?MQHHI3s!D0*8$Xff)CjHmM8}$8npEabMIIMGIg& z1NW=zY<+EUq)xb?TtW8XTpo5|i?ZPv|H9jhO0_SbgzTki%JL#|h$ z*QPxvJ)UxTYiYvF<~hm+^=!zJ0bEnu$Q`}?In+nTYwTJ?Dse1&(6O8ZF5204HYeud z+A;Js%K+IZuR%0s??9TNj%_rnGz19xDzE_SKCrnV2@$`VlJSE_n>OkyMuoWOv9qJ% z#%PqK?hpO6jgcke&HpR7;uRTL%Al~r*hSP(%6k1q)U8sbdx0%t3-$x8*C2(w9=)69 z+~eA_s=56$-4i^kijEE{aUd6Uk0?Rwcb+IU^x?EZehzKCq6e!A#${E=RB2C6Vk4J= zPeqGw7V1lAWNJirU1)Gd>W!MGyt3}I=@>w_Cs_58t#hmp#Dj{X-yJ-B*ak*5AM3A! z+!-vJP-;)9JR|TOB4#J;Ai)B;>3-4@u-PrLPRF;Z`A+KdL+bwVbN&`AC_11paI0oO zu=H{05_E~y6&IQzQFk$Lj`V7M98gZQ>ler?Wt6MFXr{JDsBf`FR_J;i<|h~D;B%WN zRFd|8RCB}5t1KrQrc{~1W3YW+!B=ODPd27MwW)L%W(dr#=vJHkq9s}s2fXE})9j-^=Rd$;>A*IJn42YYDYhU+@hbNm zEC5^Af91OGM8R8_g(=KyTpvDkri(tNM%B01vgWR9pCl$aZl{r#xn*!zIW;oR!ruiy zLnREaZuPA>V9k+CwxpU*QcsL+L61B|BaB<^0~Yn+w;js!m~lu(Tf>oklAo#TOIijE zs;M_}<3J3Z4nNq+@DGu%@{$T(GYI}ciK<~5csD&%o9q1oHb*-GEf9Fqk}h7Qbu-QG z-01eCo}X&TdW^J8zH5u?Dyt~0w#s9tBhtxhe2XGoiEn|3QtYJNz4qpJ6NZ=Ncx^Q5 z{Vx`$PAYUZoGQXioJj7wv~jf*c%9~R{VtuFNV0<2(}r`O-}!HZ)Z;RK+T9Y0Q0VL{ z-P7)IE~FM3Uoi|?&4No_6Gt&qEnx5br{4PR7PadhIN7}ri3w0nt(znQxDAHdv$IiN zO-D5e>Ov2hme%FmR6R^B@tZ5KsvK^BtFRexNdiBPYYYItT%1i)w0uI+ARrMpXI9+S z`y1`BJZasgxSTUUclm4V_OI`{?Q2Fav-zgd!OR0gD2_|CG(pM4vNDWO?t9#g(qeWL2((`XQ3jaYCtH5^=JCc1bb{e|QK zHv*4*)k{gvlBxu*#A!Ii3$A&jj7Vn?nt{(C4MwGn9KZc;-g9Zjpvm}P4-@Ihu4jsM z-+nVk(7t0ld_OjF+tC!&;xkV0g{d1YSrU{HXP^SkH8F|W($#CU47sSNXQyZ{8nLi8 zZ6%9zp5T3}I&N8^f?*eL*UxCUOwwBPeZ-~oxXbRWa8TKkBs!ri*c-y-QZ*6n4OoRv z+uY-?fe6iAF&{IxUn!Rz{6c&G$KbZ-_{}CfTGMwi^wruFP}*_P6`P9pN}bOceic9Q zVs8j>Od&zpP(q@&Y_?Qn5b12XhkVk^2DiK^>kh737T)ra47k|9*ED$-Mo+Hyz-3i* zoCJ@H7^>A@3fTq(l39GvTHYGRMveslCb>?p{US!piyu#*w=}JEcG^$*taSp4yCh{( z{?f8h5XS{)5Q|G(o1#O~52ySe>9Y3Z_QO79wy>k#8|j}i8->EXZ@E-1@8J6<3DbRN zB>ed{=n4ZG&k&+W&NC2Sy2}iWKY@&;1hOXyu-HgRu?fp|!TOG`laRzYSC`r1d|0I3 z&+>Ei*^yfOz(ptvWEz=O8@G*I8t*PthD7C;^GiW6!C}S$z^{WcV#TCG0pw0Hq zL`sLR`jSB(ZsSUC`z!hDUlwg>HVN1?tdVc^0y2lk^9MVU)JW(y zhpEfuczy;!;F23hHd$HZmV%DLofW|=l?PayUm+J;~x?#vwxI6)ADBhLg)6)NsPUp!tP_M*-xXZ1oW9eRqLceIva0Tm}$saNe+@$ zHm)Iz1@yIjOWZfnt3=e#`13PmkVkb|c;`Lh6e3x>p%ikFGg{;RO`d3gbAIZ0fNRnH zBU~Y@LCg6@tB(Dnln`If&AqD1-nDtvO@4c{|MH32+Q?xX)x_$iyI0WLI={j2YfPWr zNo?ZcsW_%c@!pT*M$K$l4{qfyT^TzkD@nK=9Y!hmo=Pof!mUlytNVS1>iLT{*1XvM zI_m)J%t(QlK#mqHfhU81=PM0K^4MJVnie)xV1pCXq?hCNg?;(Q^_9I@5r{;gSQLt^ zbnn8%dP0q?W>aWfK#bko$Wgk-e|iahRz3}6Xi>lS7-l0g)Mv9n;8bA2gI28-N8@Wc zXDjUot?6F@nfv9KJ$xCyf5i8rfc?+2$G9ur1OC^S>+9~m=QCmC zQcw82!Gs?mQb3B1;7+ENwTxd#yp=dASM<*v`g$@os}r^b*()&m64k0dGpt}Op7x&o zELS8kZXJJ0wBk=EokyKd(Eu;3KQJc7HDA$()|$;Rp+fN7#rR21d@%f=+|6|IE*S8b6gH9kC*Yx)YR96n{7brJ#!l;xGwz+#c@EyG%uPUTp| z&d-O!0v`ti!~AJ!2HkjQ6pM4kopv$MiMgZme4&+oHyasGEq*mo)Wy63hZi+Rn7ILX z`*I}Z7<$p?a6IzMigUaETY`wTPjGVlevRY;_U!V;tiJm_m6;{pPVt;*{K@~v-+8o4 z!e6daeGP0uU#Y!n|m0M7O6$Jt- z3a)$bZ2x$=c$3Nu;?qzJThB3J+Ccp2$a_`3JtqJz#M{7S3B!;YoAzPtwUBf zQp(AjNAl0DH=qK1N`F7`pNIC}^q_gxxDrE}l$_!zS0+sV%D?V_m3=l*1`Cjr)$@0gnS-yWlY)ecsS~Q zNmqR_$t!X|*g}n2m`m$nI#}LV;2Kj7XareDB8Ui-U4FE8c8Zl&)OcVy_ImJ& zroS+JznhOsgk5P-TvV2-U$1jW5hGE1zCGJJ*GF6Ru$WyLtI)af+b`^J^XYA~9@$Qg zcdl2f-aGgaa12vc(FX?LsD?7hiW{}f42$loo7r*bTpRj}p9=w2BLK+@z+(=}&G_J@ zI`JsIj&c?hv;MZm8y7DajQQeCb$@xVH+s5{?z1Vv>7W|N52iI=Fj*c|HXOjre4zEB zUp=gSHr8!yaQqzH8Y@X4P58WWGmbmL(*+W(teieyfeT!7L@f?h)1Ou}zFK<c3Wrl#KvrR_st11F5fh$-FNCR z%-T7K&=BC(^J${$u>eElvP*^wlf3DP&$MkD7VduRl7b*YMeld;r!KWJ+HWK9P&*c7 zrld$;C2;Qhu~$`Q{PudS`7s&}K3Z)xQi`tZL?4QJ2Uj9qa&ocwq@b1Qnw?v%SKVH3 z#IcU7B^3`Qd`{7q(D&w+7*oB7WdFm)v6vA&He-MUVfe?3J8Z{@aW*#m8Cpq2Y+%(( zQ~A1Q=;M3(lKUm5u3s!6Pla}MKTcG|A<+*%!1ws07h||UH&#cGR) zfn=Y^_3VOlhq-6;)LdRw3J@kM?T^pQymjK{BnHZQ5^}1)xo7gN3YJ9r+;8 zcok`D#cxq**y>fT^woj`dB!OSR*>HDe@mS5=^o5~iiUM;}w@{HC5P zX)~+HkKXu=B^n#>x{>{P`hWAek1oO=zhID1*V{!aIFn$4p~%P^%7>+Mrid7_#qc5E)w3r4eIpi z)ah|=*-u+)s9+h80s_>=QOn%KE~xCbOI15CEkj3yY^m$Y6j7=*TCC=&5hj%FDb=ED zTf*Jcf|h#L%f&v2{rP$9+!7n-0`&W;VQv29F@P5wxpFF6)x6cO1wWiIQ&u7ud>_VBzM)r6)HxJ= z)2CsTp4oS`BfelPp16M?(ab-dHTCt3-?AKmw8*-vyP(jJb0c|Z985Ac5D$Y2FrdlXE^?lsD!@c69QbH>W#)CbtK1+(DFfqE>4`U^Nfy zBr%S1_C9#qimam{TQ;(>dV(KaUpfhhu-je>@Yx}Os@>B!hdlq*nbxIlA)agsw=DW)W&9QK zWN1@mxD3UqiM#el>0V9>FPlBN;7I>0gTOAGRq)HY5A*@d-`U@Xmt^X$?xU^xc}sNy z;1Pq$H{r)k^;{RAzLsDZ%Qq4~;Q92dJM0GX)l~6;H{Q9-DB)82T0LB!K$^zOWmkZME;OKf~HDenb(vK4{VtP$FNLM){nIPb=iITuSNd zQ!OE|{tOjY!&Xlp9~o(5+j&hr)cl0gMdz;_T|ZX|ycN!1>Vqc-%-DnivbBHk_mHeJ zU}r%cND5*#zbPrqqTm42H~-)lSIbAVEf9Y}^3OVrpY~Z^egdFK`I4MI_UgqK={57J z?LUS-_QZo;gv7PPG8Pl64}Szpg_eJMdlXae!FEqY5H~pWh=xGxdHyK^cT8?+nofU@XuX$S?6}y9*f8(6{Rz6GKr)Ni4OeHNj0g4 zsCDnm?bOWmftc^M8*4?eGKLi(EO5_>3`dJ|Eb3l$X&#$;HGcJ^x6q45x~m)x;_0A* zI7V(pMDa6Xl=#|3qWt*IBO7$_<1toXl@aeYU-90?X@|`>>2n@BHOkkVOFELc9vuNc z*UW3(6X_ZM|0?^xzT_!x!-Ti;W9%o%zY;O)9o@|lmPdRrtDR3rui%&!cdGv0@v6Dq zR0ipT1!SScQ&wyp3|^#*xVjgO@e-;GFnyT{0V|{-cylVJN0mZr*^zy7Dd{Fz}#4=LWW`IPD-@i45foV#bZ(MqM-D_d52owwqV=iM{NJ^%EG zKZRzZWP!CMyG zBUE$V9Pt-r`$=zlF(Y=+Gka)##(lT`*qtzi13kFW*7~gzoL6T@E&!uT>V#oX{x?qFTSQrp^^miHxutD1=Zd&>HW+QH16zvOxj(sw=V%$-G;SZv?* zA)p_2F4PxVw~%A@Tg;U{*}cR6je$Rg6CYTGn$!5Ogpgyr5D1UC$;5Zmt#U_dN1?U)Xm_KJhu8=kHgJ8gFfmcXf!mIiHzXK9TG?FSOKl&McuZ+ODG@r z#tV0DhjMO>?B5^2_+|nPyH{7RSIOR0XV@~4aUNwD#0gN`O-j`7DZE$+Ti4^!>)>+= zor77N*B}G_(ssSc_Tl(!5X7(nJJk$$Agl{3SKq+6e!)9S)>3cy43Z!=MQam9&CeZ< z+;OqLsC}9B0k%6NUS15%y%?Hu`J?`Vihj|Sv2Ut?>5H`=)8kjV@pu~$3%9MagOfwI-0b|r4lTB#Db*{@b!J5@0u{I#A6HTOp;ZDN*1A}KcyQg zmlzS=bB|N=aQSYPPXgQwKh*u#Zm>Z0lWMJYG`>?8)FcN@GHQKi*8F%Z*A#V~W+zU} zdNp-`^=e(W6fdVBUFwzRpIU(UG?53KYkaRhb#?JN&nJ7~2{0;DoV!CkC3D}Xx^W^{ zD|62P|MFM6*~!=YD-#TS{BMQsEIEESaDLu6Qr4B7-mP71J85r|gdl2wZ=G?@D5GD) zicj^VH6mX*Sl#aSl6WTROCBI`lv$)gI+TB`(s=5U{Jj$luzWrn36Bmz@9yiC+!oQ= zi$2Z@OK#hSn(+NNC!R0R177c4$!ageDy%F?XJ^Vku6TdJdoi1e4F1uik`nr~G84Di z@n~m2j`HVWhM1B1vuT>8f27=HAm!SRx7WG*7nk0&0>YH6F5S(A8Qez6B&hH!#4`qD zVNVK5$~m9~k(fWHWSRN91=S9g? zz;Rf`uuT2Y`{-`|@hTRqzl$kjBbPoX!V^xetx#+6(d-TkSW+zT&NCj>tLDV8yi#wx zC@DPv1?2l9_Y^ccfz8Z(vNxxiQ(HVLI!Ck0 zWxMMG{-WV8qt?|C7o3R2=O;ap$QLkUyVXo{mz41U$4JU)>Tt##(Z!}~``-hNtG2Ib zGsz8*PwB^Z+99iF-PJ;O9v$6c*IF&=NXo3XUNyJD`#ObK`gV1t^+K|!eRga=SE7-pesJU=2pv(wiq8Z~(Jyk7Y!;86K{kcr~k2apqKlgz2GP-aO&ym$RIXYFh-v;Yb-jZKlr>Sl#gs8obuOh4CAEGy zp!vEM?%|>~pE3J$XN-{L`-6M%^?ifgceB?8qm&4KTXLRA9>)EdO33@z*vPmkaDB4XZ+2MOYxBs$b%LlhE`2-=A}ES1yvQ2v4Wm6 z$+0=<1k0S-0BITuk8)@%ns zp#MIj=+6OTN3nR|sxR#5`m=9QE{INf|NRL<+LP&Ct=He zjN9YsSzf)(V7=JZm{{$YT{|0D;Y`kNIn9`jHP39YPasV`Q>hsmKfkk2RR%885I+L1 zsf#V<`E4OPu{J7j zZ&k-tuEPRRX%8=noCwl7UbfMy>}WTqR{|>0 zdikE(aO7v66llxgGL*0SLTM$1FO|Jn|I^f<|GUwpq2}j0s)uvVod{ogSW4A1kvihA zef572)~YA8sN41ei)!#pJbpBpi5Kf4u<@taJK@|V9rA)v<nP)$BEp$|xI#;hHMD_-YvKnQOh6F8$hQ_Sq%3EVGV2@+zmDeE>kl0a@yJ^9L69pz2$0 zB2vglMWPe?l;8yph^I)rN|dzw%XRbo^kJ6PKD#ytL299uyQd$%l}=(2^v)%BPO@iY z`RP{BR4Z^}*$7_MtPCLf3A%`)-@?X?L3jU%@{YB*q*_Hxa_Oz~(3PU(Yw_2a{w@Ix) zrPm#k_HIv#X|-x><%O~uVo>krD{B&weWfRKFwTBIf(s-yG7d?J8m;U45%c{!zmzPhv zf2G{h538YbsV?lK*-ntR?fB9dAr?64%LurIDdT<5)8;lZ)|4^WgGj8TxagsRk*_TC z!=lELcSnA3#L&G}P^x`yHAFohhD?(QLu9wC)2cIP{rmA&Q4xb%k}?sB4N*5X0)@S$ z$F5=pT+8Dctp2+)Aj6Drg6~qq7qcFA7*!Gu4=83borPK zb%vd(9++WOyWMx+@fPQz_bFC6HX*dri`O4i!ESJ5_o*=6ZE5dRhsi*mCb9^<2|!x$ z^_}4Z?dc51I?B@J(c<&hwNr|q=sZ+B*0QobAftfm6LZ(k3TofD{oYs4Hh0XMqdn^Q zyFTubEp17dR&6-LU3u%H|5_7q)pzZK95Z)u`SxzAF(2iaaQVmbzn2Wc4sJ_{{r*!l zRB?0oEzl*+YUyo`2$sNLrVPhSP$U_bh*=uFCpHfqAfA}wGuPcy~L z7%QO#GB=P_k3>KzhjBQ*uAzx>`aKVo!YM!XJG2^c_NwVU0Hfxw_V_r$2FgOcolS#S z(a(Z&_tXUjR_18l{<>z@)^X$+n`YNTGs8Qv0|-4{YUU0-<0BP$Rh}{feo3;m^s(Pz zy1oi*eIgw@ni4gy*@RQ=`+m%pr4o0>#SrCNqK01XPAiV{KCaLif3QCkh~i5R6Ye$bn*DPZz_iZ0iUUJF2zGO)lh(OT&j%mX`{rxLm9j?# zBI4EK3Oho-!A!hA`E;M>=zzXXzx+Y^KY5g;@gqjz{$M2s7n^dUk8j@23}gtTbw#w##8C^^pdPl@Giyg&23> zUV1flYWWkxo)JfMD8*tQ$5xq{BB5IL0(6KYUaZMl=BU5>WWj+jiJgu9g(4 ziPF{o+KhuJYCbZmQ@b+0254G;h=ilt$dZK|4|*pSjr3m(<#_&+Hq68BDL~x@f58i3 z+vEXl#QtQU^)i_OcNv}43%iunWtljhG;}?(!sn@BDast*0$_LxO zQ|Ns7BX4rJuhg1Kbv$$9$H#v&sUF=%7~wbgh}q|@?cx6LiaH)@CNV~Owl9c9Va zG{g>Eg18go^Y|%Z%wf1nG#lrepy1^EeNFwwwbjwwL`k;bRPnkVB;`AmorJZ;tOmzB1Bs7-U>gKDHqM9zJNtg7 zYO`$G>+|$>_G_7ZM#?pYz4iL0POl|Jk3!Tyj0zV5>3-grH17AI4#sa>HSy!r;cB~r z6T|5uoiy%qwMI^Ha$JjYIG7U|376<`VOPI_;Man`_Y)dEP9L%5qTIv@nI@IPHk3ZV zinlydYp+{FiYnAkLvnqe4ZYm6IntToq1>gVt@hC6JQRNVLG;+5 zw#Iyj$CzhH>7KRR0-|l;V^pwdU?uE~O8u{=5r_~>mS1Bz8m7 zWi6ns$k1w$xWEDYX7O{ju4T$zR*g~XdT-m6GSmvgu7BGB#-QZP*f451uUI^)%{R)j z%b2N6J;U^Z-zewG{5CRyX^|pG`DpX;fZ=WlZ{?VwPPL~@%V_6cdNZ2!VqMq<37w!K zpBtUPQuX$qd6RRhhuuxl6%LVp|3q;G+Am>0$ke&7p}imUY+9&`-v_uV!CvtqEOP%a zb@Ok1b{iUH3bZ{S_h6sI?aD<>Fg!T~}(K z_g*yd%~avTAc;j zA@=uvL)f4Z#yq-nMWinbuEL)OEJ zk*m)g1F(@)@YOH?i*Xlbt;QW1jk(Lg=lw#=wi(AOw3B-uoDcZa8fY50AhO5OwdV@l>+BYQ5w3hhVCJkU zRAdD*4qy4+T_3H^3#_x7@JS5$e8Bbi_uSUg`V&fhC7N68f>bhf*ZoW?^rBjcJ0Mi7 z3<`&m6mC9JOTf?W8|X3`c)}|pg&Q%RF~5mdEO0$gmKP|P{bK3_-gZ}jAxH8G9z6PG z-1DqBUsr=5&ZS_%9q0!i-|;1p9)j|E_ouL$mDj(dtR=s{8@=dq=JnpcfKz+6N#kh+ zTLN)CbQ8c!A*qX#eZXPQSFXsrun`Z^<%q29fOwAyJK4!=v>W|CegKBq)}|6OcZu8|2vL8E6gXt7d)Wd!OlPL z4an^+$!ZWvgDzD<23o6Nw|QVb>B-$2vZO;pK&t?5_Sbo#QnnEzGmD8?&}_0EJrjep zti+&y-2IPh*J}kXC27~Fb}6?X`@Hi5)*^H@AIERe;x0j%%o9Dz0irx(%fPG1UND$l zovm!(FSvtl@ALw*bpRKaxj4doYKZ9$zKP9Hflc|jmeIdNzDnJ=;#Y=Ft11EC`hb3@)fNil=#z;c@n+4 z{Wc@t;n-!yY<#R)#$2jJ)G5$N^Ko(-MuQYU5d4>)Fvr}7&{4`) zIL4%|2yVOLFkF-3`!(SAmmyYxp6K-!nK$NO@qB>_Ce@Mv3$+scDpRs*+<_9AgS$ zKtq;`3bj`c%cYu;m+T0J@3`KQ9C3^DWfg25$P#>Rmur ze^j?>hX7o4_w9#jmAE=t1?Yg7sCxG>%Tbd*jG^cMrq1$*zt;AlTw$PjrHo!37ZdIUx%vQ111NIJ=K@I5k6&)@4JL*IoE^4N8Uvhkd ztF}YdZFiMc7()xsG9B%y$>!IMZQKKnW!#wh){JJBp>%H}9MO<)8U6iRzHM$qg79fa zvEhm8L8bqrzkKI*9f zE(qsm@JxP5%l9v=K|ROEPlxWtUI&JAV(LX<{P$+h?o6KExcCqF=vEll(a?lRj9Zqv z)le>NtUFY-pB5dB1qFTT$MB3}5ncx{pg5t5s$tQF3so1c=qNAi z(|ekEHyySGqt2p1=Xu}6M;u}i+1*c~iK~W>1I$o6*D5_bv5Ir=>h5RWB`od3Y=8$JJ|K*dSz4=7`0+vy7ji!Na=&CCN<)g z$D3ZAvIjlHVXvt(p~23r7@}jZCgPrpbLMdmL%XKkUh_n?`mz(x9sblz{;b$x`P+jw zmtcmtXdi^g+VFxd!n(lBA?{k=hoFnC59d?n+^_$WgHBlFzMHqnKb#3Ed5ijzXfYNn zJ&+A#(dmhm*4i0`qcf`G5%l(afh2<s*F6L&Yk#`{B39TT!0r;YHc$)i(&)3I@lE(9cHW)msSb5vOf_s9Tr(q#VvjHJcJwQH2u4$%bLaCQoXPQ+jjc!ebX#3n8=z=^-H!#?e+SY#n4;g8@&=V87 ztHJ77Xgy@=#rD?ofV-u1WPPy1YMypNAI6H%|9zxkyrr!%Cd@dx)ED*)w;AR8)j7ipYv?*!0&(XX;b+ z8z6(U&Z22bs@cYsEKm*v`6}?Hk(wTM>dMyv1|lN-Ll8S>ld8V_5`N^4g4yuEU?#-) z^2bVmt(D?SpXIQdCY6}Ueu}+nNy253Nu@p~-PDb~gXR3Um@DB3AR}(;BzJ4KJXy7m zH^cz!>PG!;qM=s&RzO;TADgIm3}lX2lqv&O-JN!((s~*-pQCxJgh$Kt`whGWys?X8 z3tYvD5AGU_2zyRGdK1&uIPWY&gIxtTZqh^Hm2-j)RiK zRNaE`j9y>xOhcK)521SqqjzFj_Pd;NJHyG^LzF#BaD!X7Wg>z8K}xLhO(<#IjwqNc zDXh2nL3{+y`kG3h?3#Sye)vs;FR{Y2lvu4zvRFBOsH}sYI+Fq-KlwIZ$cpw^H)m|L z+a}QnNDzTrIz1IkYJK&yK%P%wneHD@&2kmb8E@kGD)cvEN23_l=+(=4hdUK5pL+)F?;mT>j6U1Fc13M~%*lLy zfNW#+D0G)>B-iFq$qmwm|J=z1hZ>k&Fv|oSB_Ln<`YK?UUtgcYk7#uPMEL>;Ja=T@ z+_f)`A&fInSdK)Uiq+u`)2cNBv+smw0L{a(_;FmN(jLRbNK5&JI*TlqGsl48%iP!d z{(@QQ0vkyZQ``YuwGu53m9rlH=vn^{ErSDChP|P~GB9AyTL<+1n2Lnyp8n7~sCD6| zdkJd+OQ}o0SwSQ;W0Wal5m`{+hcKR+JO$7EVvgoSSnFE!p&Z#aSg3ard&^K+oLI3& z8v3Qgj6|bf8$SJ&9g9VEc~7i5fS0dB@-^$kH`O2vXzXg_1MSEM;Rmn%T>1JIW&6(s z86q!C<27l<g@5dr{{;zb@4B|LJ{bql@gNcY!L}ECW!kQYHaI z+Ye1|YaPF_&~*hyQ@(>`*I#U^EF07Q$i@<5qCTE(oJAedU_O&h^|)s#-7C4fHd*E4 zEwbK-!~RJ4o5E@sFgZUi$z?tydRDWBL~H!s=Hm(-z#0#iW~@@2p=~yPM84HIsQjAz zzVcDOtjul%V~tJK)srb?0T5lxexVtdlpe3ZDh1!H|8%Xx)znl<>Ty51Gf=ob1D_`q zQ$fWr(oCLSr~EN9RUHY#)V7~2i&q~^xlXd!$0=k##y5%h_GiLg{d&~|`sRG$PcI<; z$lod}b5SKBy)peQFY1b+dmPo(QJPP)q*F)B0z-=ZP~{c;^2~tW7=Z81Oe+>3yhbS~ z=b&~%3v}aXMtCsHdEP9G4F)XnM1<+Q^l5kVapO)ufayd5UQG6xAE?UhJO0;tgVEKF zQfAq!X(}){(T@3myYj`0u?i7=1qc5grvfbQK4tA(s>eAwpj4xm`S)-ADi~dQ2+U%X ztBz5rC*WIEwFp%Kmom)VX-5_%KxC*i1^{8ip+(XwMfY;P#Rz$+hnNS-?gv zeU$ErGA2Mu2~#(S$X7%5vFyh-HiVf{ka1#DBW0J(P#$W6dbLIqCANN4&|+1YkyS^Z zsjYh+MIC96vs{{6F_7Q>r0nC(5zB5ymGx(AvBOEY+!A7BgW9!}TXy!$n zKMk<9{j($fq1{gijM3M`ug+z&J4~l80-nKt8Hqbv#A)H-aRf2fp8<{2bzkKUkQQw! z$4}z7%7vefr_^4_3VB&<3|bSml-Fu8WP<&Bq-7Q0aIdM?px2b!aG-Y;>ny(Bhz8Nf zFYfjqAV71V$!L$w-y8-s#MjksuzDEz!z>rvgK^2ZTYBbsa=`(Ps){n)+UOf+T`NV` zolyS7al8Q}MX$6G4Xm0LmZb%>j@i*jb?(BA%)K*!)e?;IhQRNvFlyHC@SMmLtE%M$6m8HeIfN<|2LjhPq05aK9N&o7nj+z>3`auwj6dVjeIW7KBxbgAa=+1>YrX>a3Fxb^yeJ{zwUFxXS0e+UA%0Vvxy zvC&!^q&}e!Yfw>ZD>tJp)E#zaLm=Rrm23pgY)DW^rFykmu2IU%xxDmTD z^8I0qg~`GJBPh!GQ>K74Jfa90xb}AZkwzpdU*Ky2H@=_x*;MY*!kn;sEGBeRb_R@K zMOlKdGpW(;1L`iEr2g&{`H^?GK;*Xo_WgSyAGgznJaLtT?}r4UpP;bfp{soQ7kxs^D5r zaeU&Bp^bm@d@BL%R#`U)4(AZoUJ;{tAK?WuS$afPO z^h`fFl)-t!)SYV9GT5+i1M4AZX`n;{BNGABaAo`9pzDiSb*Rpg$5|A!vH<7RkF!Ep z^sYblA?U?^V8nf;_oBaE66*aF&2@K)Hu$LG{nY}v4U@1eWnF!PU{iREe8b)PvTdEi z!34qhJg4wGf^Ff4l$!#i+_9}Lqw%|TIDS&51Fd1+9xt^O&mJVqQ;F#o8yR!$4~Z}W z+s1~R`a0#VRTM@8b^a_7ssvw|2n@NgUIhxAY>{)UM9-eaKi&h57*DsgF*Eju&7TDo z9?oou&U)=q04eK66&|!5{f?vO#|~-ThB~wI*hZ~TeIUau@kU45Xl7iGQ}xslU_{oU zMon~WYFUY%o~4yvy-H5TE`h-)K;~ZB0lvPEK_V;XpW~Rww3=9(3P{sPez%IFyPe7)U^nL565uGDt{7YEg+2j0(s+B_NPM5eV}TBuK&#LP7`xes{Ee-}NqC-@|VG zkN=K49&YsMll!@@&vjnsy}0+Qzm_%~z|tmYw33P3`7&8w@B`KkOYY*N)er??mB3xT z7`sKaC|=V_S7;9qE!{xz2KKR$iiCq81F=*nq3mX8h@KVsJgYXuk7Qu@l`#W zr0N~(Sep!TMfz=p{;~EB$_QSLb)3W4g`X+Y(jz8~U|R5UHA=y7>erB9`dK9X<+59aw|G1Z^RD`;@Y&1C z+0XO{${$Ef`PSCJFU1o6!;}7;WB$I+UN`>wDOdE@=;hyE-m289AU`an6Zg}b+AafR zC$qFya%3AA5;WDmOAKsNzs}xMeUG*dPzHUe-gf3+IZvU)`PWl6qp2sEWYPU^CW!U@?~4IU~MKIX*j#cLx2)Z+yiorPx;15MNAoBUpx@W=i)4RNST7+q|m0IMRBN zrchO^zZS$O#U;wukL;1GN0;pphz@RQ?@!v%Wf~V2+^o%MvvO{@0fmoicaCfG3~FWi zwFw@Y$)nyYyQpE%W}S#)EuVf<_;}m#LA^-5a%u~F>hA3bE@)|GC>Zd)cpFc?aGH6( zY`O3AHld+o8e4i*(pmr$`{ExrF_unF19rpH3&Q-dFB}!98OBxRz|(PI5x9ssn+RN4 zSJf;pW)oUsAIfSt4~f>;OssWwMqGcOVPwO6#}Y`_ANJei#s8|+|5>7jr{(PN+A_&$ zsOOalzSZWUk@6t|)Fk{-bjnNk+r6xca;VQ+1KXbu6K#0M$#y~8nJF(Ta1@cZ-<6Sa z|1r}w|MdR`6BO~!XUvzj&c?QlK*suLkUyk)rce-zcI!|}GQyTYD7G};*;(WurTh=2r z0SNK+)l<{OSjj_E+j&EIGMj#$CR_i>acTFBGBc%;Kwyv;FWbf%J^`^f3RC77_^w)* z7aP#~WuwB-^>#ml-PsTQ*6c*sc>rLNU)8wb40dL;|5hzG4uGY2F?lz4&W)3Fe}8if zqT*RLZA`s#*`^2(K~zUmx^ya@q&S~@9x!bubHJvbV0;ykm;8Q#^HPzAY;$+$7$%0RkSWvm{9pZNgLg#0{ ze}{JcZoUyOXc+sY><(4D9{I}OSA3x3q$lOePF1_j(ZG#*$v&e(Tyh1DfNz5S=!u)D zQ4C!fdkc)CimvQ+~ z$ZJ`jBxs5pCa%6`*ol62t0-FsnO7vK?E zUBU!X`TY}!=@esC4r8um-NEz26H_lQP=%1x8c{(la*VqO_% za>so)crW)9!^o_Alk&dPu+(a-hHzmWYuVaV6L@cDGP@*~{+)1LB^cMbq=ioAbu)k; zC?B`~<>j|+zk^($`a!23V*~0kc74SMP>ceTB5&1EwmZX zHqf;>bk4&XO_Mr~IBQ&y9Ir**v)784tJRg2K_)v*aVwjiJgf+$Xp0}D!p5o&8O;vm zYB;uho3L0F2dU}H2(LS2xM*waX%Xu_bps5$jy)Tc%e(-sX8oJz5nv*rN2kYIP||3h zX};PIc`Y8Xqm3;9>g;_ESZ`lFz^DNxnCpJ4s$yFb`q@aHo2_xt^cEq)hw9As>nG?k3Y56 z>GBQt1e3zK&70}BYs-Ki(zDZHNdS1>5)`7OTrIV~F|=ydhIaFxb<|$5={!3ovzB21}6S-OFkwxCHD= zRuwiN1?nKx&RE~nGq9?2YPBQA8PF#4Kmq8eyAKw^D?B8Z{bBT)dKUOeD@VYN+gBm$ zXczCiw(6?04xMbc5PO|fcCoX8Z{6FNgB&#YI`39WwWp)Wb;1!7%G2H4LoV?7AI)_y z%NmB)!hSEs&JHA_4DP0(GOGSdjSBM?)q=s{+cH~M)^Iy)Lo z{5SfF3X48pW*q>&M)`gVcXFfO{Zh6%2;^7=_tIsv^tv9+@ z7HRkl8~m&Nx>tP)^@5*w5K`GGi)2dxj<;H3Q<(qFmr{@;V6Ft;TzC{Sgg!FcrsX5E zI?L~5q&G=B`v-M-_AAIK@f7?q_}iniIr8T^wzq&BuHV7J4G^$b4W|wpb*f#3+k#!< z^Ma4wmiUR}GsXw6?gG>8S;g%C7PmxImWEqh=ltm{FD_ZA z>jM>hbx(<4Pc504I`)EDHa+}GvU9{ACThH>j`2;ns$Wj!5eVUWErrl&_*(TU}=$MRcY+syJsQc`p6& z#0&Cr@bByd$f<$&OUd2;K793kO9b&<+=lPh*z^RzH4Z@7UZ90dhtEK;M1+iS3`3ZwIu`UVFv*WG~}$Y}@p%RcO#l*=?*8mrU-D9EfzpeOMS? z%nWQx+9On{Ar2_S+UwRd=*z-WjE$B(g!hQVe#QmNR|4YuP{a1~Q=9(($9p{W%TnmV zW!U+pXM}tOON>b+Pi`L%tGQY8{}dJXnU?9HkN7qV>f^P&Uu=t18ogQ| zUQa!g5X$Va$E_)Gw>z4Pbt+DZI`7{Xu(+VV`=) z*ap;k->9Up;GPUKzg7K)wv1a%S>$;iWBxu=Dh_vi882p9FrM(-U!3G_DQsWWr!~}{ zdd@R**RZjpO3|9{g9`j0nzs`-ENQ~J{ghu+70QNQVyJ*Kx8#aM_4y9I4_ooWFlL! zilm3#)Z3!+V{8s&;<9P#+CcwESFj|~0Q4DN!bv$ITMQ6cvE-GGmOGdRo-0lIZ*zI*3cj$LX9fT@`D@sdkqiv z^9HMe(C6ND{4rm!W<>f$ZSTy{^=v@MF0Bd|>FNxGiQf&qnI=q^pR8zCXoBRJjgahi;t@C_`nbOkS)-4LY>XIq8UP|odRm)VqTnh=WX%8~ z`#*Z%aU&;LKzQW<_actF?h(tQRIvZ$dn8xNemYI+kV-JGTrwZv|M}zGufqqTq3K>b zFu!ZHBFpI^>+fw;w?zX&7R^Cw&t`XW_$k!C2w8FcCAl4#FSi4$CnBeJ4ZaUA_S-MF z1GCc&$CV7s!eJ+xF8dZm0Bo7g&JU#Ejg`!&!T&D}^Uy<`BFOKC72Y9{9-j+o^7jqR zOmjql>ELk&2`(FO;9q)L9xOandH9QWI}E?#i$Y$(_7zADq1Wr;e|(#%rsks!iYEN0zqbDBj$h*Vxg^ zkFb`Wj=4Z>hb;rNaopR&zo8n!%OY6s93&#@+TA70Wz5mp<7=~b)5Vfn)UEpE8Ef7A z`CYGi2NuN|-_neG-ILtMDUAj{j}Zs*=4+m$+MyUB(~4;#$R9IRYi(&#gA38OKh0;K ztpN`JysLYtQiF@HY^lk0kY({N->zA9!doq4dkm0iUy8?;tNALKa{wOe?^Qy3StgzD z_aE7zL0#Gvfq?2_z7p13FR0@-k1xDjituiS4lW$oKA!EeIj(&F*U!d_iAp;TIT0FZ z&dt$GV`_JL`A)MPJb`mU^(n;VktSHQ{nOf;kdVl>+bmERbk8s?~-ns4$y(6I{_zxmG*fmPLEn;)j#p9W%0Q_qobkq&5L_4xO z-!$%U;H~;i6OHfAtA`8rQ*)fTH#HrFisO$7OuM-;!(Nm*7P}j$XFt-hnH?YLSo8%s z9c$MC={hnuykkC?x;$%ov|xRfy=X7tSfAne_FcBSQnNI(a1uSjS*Jj0W_(U+dqkbx z*VkL3HF@hVA3Y^xqGtofYWyN+Z^tA_Z`#{A`tD1HKdXDs`{C&PTN-+vt>t=UbZpW* zq3~JR`x`QuRn@GcVH$+$>;FTE9_05vQ`ydL-pQYvHklv)bei~`7MnN701q-?@i$KO zDNoDtB%lobmic8N7dyMkqmo-L;EOvK@6@w0E5B-(Q%QryPjfjw3bov2{nr7TWA35_ zg@rzxZmd{6Z!=pfc+5%#Ul%q9n+G_Cc3wtS<|@&+7LS$(FV}K8>dL3MCy3a&9N%R4 zL}PTo?-rt`j*IIE&E?3IlgoJm($kCNv1$wMQ}%hhUPPvbQSF9ZiDY1ZrKOxc=a*2f zWMpIWvop0WL#a|<85=yB!K0l@K7Wu zLzn0D1P#TczE*$CX0R*nqmKQF#xg^&N=+V+KMa>^96XmVd=`z(-{(~TS+lZZpeo1; zel2WfX8Q1Pe#i75Up(4!UbRG;_ko2k&-Ik&`qhukETTxNm8DzzD~YI0UJDnMWz(Lk zGMxgp$2zfkFk|`=Vi>T$dRKu5+!jcO>?I)3BKjrNJ0DF2Xsk7sBno{9FWJCj3C7>{ z=FwCq-hZ^e+5`LR1>F~gzqT8XVGSpq;%84YV4aK$E_7zeBe3crp_(4;WqVj`d)+5x z{YH!QyIy{9`=wk7Z9ci>_c5KylJKB!2O8WV251Zo-4J6~_n-^@%6WSyBMutSI_zSO z*l}fCC(^EzL2wFZTSwJE`inl2u}=UQi)(xD;%71YsL005rvfnvO4Z4`$8%fnK&Gy& zJ|$}d7e;(W{`zcZbZup+CB3qA+Oj<5Os_&ycef`Le)`@#oo2~U)kRq1Pw@WEbB-T8 zTmaqGt%5pqH!q27jj&n1*|Mu@Ru-_}exmhJ3{KC6tp@ahC5dto-tQUm0zH*3U zh{vY~GL<5

(sVDq=7EQ3?|3DQ;G~RjaSK1Xckz^2$tg(Y#_)Rj{5YbSnp7Ea?Ln z%lH7svTjrWo-y0rO#h~|bcJj7+DeVI8*EqrI1SKO>X?L4q6f(kSR<9RT zwmW5hTicm-DcxZI(fB=-8yba($eNgT{^x2vo0q4q&J}-`$yOE3)&NFaWV5N z!kddG;b(Hz{N)1BTIxgD*kk>!S$G`{X4|bLc;5~`t(H~Trx223z)QJo5_h?iz&W10 zUK7o;Ru~}}via>&k_#SLH)72wboNiS5&l8zLkb@HizNa2)~^_fdLz_fXFu2A&f_cT zCA_E6asSKo@R!>h#Oi5UE|EUkQ>zyvS{!7Q`kUEzq5rDM?4u;$B)78ey><4F zT>K;c>J-HD8Dbio54E=Wsfua!gUVRFWPQlEdnuyF<_jK#$dIo))?<4r0RH|57~ovRozWIm@!#fwm@UzMuRmK@UiZi_v|oLm*5eU>PrN+ z{YM9E>ARe5`z-lr$7_o|i1~PE%_R@lSg9oFc-G;SLMLf{(U`j@9&0*v_kl3qkcw$Z z36k@%uPhUnZN^gG|8kbUyhHR&$iNwBwhiwNq;vsB+o~R}g^r9AF{U7Zk7djG*ymd( z^#8Hf&V+)&i6vUjl@yGhxF_N2_w{zJk;oQ*sASrvswO|1$-w8Ea>8_UcAbLI)i-|T z{)jiA9$0IKcz9acC6x&p6`Ht} zeH&Qst<9olni1Gj!RgtF)o71yjGzzxDqJtldY=X9J^I+63fT50r0aoFEKtDi;CNX| z?mi1-bwZR$sF z^_?SfM}$W>Xmc|hoiLfEgg@Y9rFLzLPcGbM;HR25H?pnG=Bv(=3j6EWgUNS9R%)>h z^up6*T;pMwF4lK+FMqfQMQDN5eLE_w5VfZw>>E10Oq20emdhRnEscMQ)~t*+BC}whVzPI4xYv z)2}X1>v?(KI!{(iYhz9%I(i(uTDbqeG^kOKIZc0fdFhLHXUd|_pTo&(FX8fO=pKvm z#4oF0!{XIu>TfPBOBzQkU12Z?+~Z$VyXh?4E|35aYUgQzRxVXlt6AN&phHNb?ZY4O zSWOIdHUeI2QuiytDIY$%2PqKjOzUv6ku`Wn&NW2PQ%Taf_!g&pD^%(G4|wcV0>ER7 zR43V5%$|(nR5*6(pn=&w1f9w20|wZlss#uzz`i$z8u+;EOaiL+v*f~lF;P1*k$a&r zQEeZB&*vJD=Yd7aP@9+K;Nyz5(FP(vv?N^pO*k^nQ|5{QqX~6O)*p}W3ot!QmoXgEr zK~_L3Jd=}pIpKH;q` zV_8@)*29!C&Ee*fW~*j~H2qz5Dm&l)t(%J@I_L~k_V7BVa%*2y;~Y6F!$3}-!$Oq&l_9_yV(rZsvDQeJm?#x{MHjV;m$s7d#yzOz04Up81g;00Y}%a{%ikBt;1sY+y4fCsKvJhB0NvY>I(x}2ar zvD}%=gL^VuhMI-T<6&`R>wGv-`--epuHzX;5eUlA1v68V^a(dC|>%Oo}MbSzGz$ zD{xmClXSO6h%+SE?o|(o+gW^3Is4@pjNQyyv)yO4{VV5E2Y`SMWEFkTzdrk*e-+1S z1fKUF9NnMnTmZGF=31xkHzk%+S>bjDwU^*NlZPE`#B|!=GzeGCa>HJ>%Z^{j_KmUP z=$PkMdWW3-oc)#W66OD!{fFo3L&nVxOJ=-e2FPaw|1o>@K8lR!_5O?Huc^x7YdO`! z^9&feLOkEkpnDeD>w7Ik6kC}^**&VxbW=V>0`k`mCm?@?(O5T9(aZV{)xVRR!r!J$ zrl~qEQ1+VJYw@TI$X+hVeXKrCtEo&OABQTPd~C(zuQs~cc!Y9QwEHMjmcmF4gLIxk z8;^AJ3UEwk^Kk9S`1VHfHv8jH!p8kpxbc%PGCRAR$E7)@y7^Z70_#JKRltz|SIbXE+Gn*diJM!2{I#@v_l=G}<*&I2&Rk$r zJrU^8w1b|nw3EO^i;p|jhuRjMI-X6aq)w&sKT{U;e;pv17f2y<@_tz8*lW7ge^IF+ zRJf8l-6&(3siG70?Ru_-mB@~S~f1(i}@gbT^3l)v;BNLCCAnW5?YM)c4kg1 zA%cPGp$?ndX~@c4TbLR$_x5X5v+GAy)Tv9F?`#KgjORa!?-lo&O+PoV{C~tR%QO5D z1e3Ka?Z|x?`nMBStjFx^X4!=9H-;ZOtp)Gm2rCQK{m5|AAa|0RvpzB|99uD{uSAl& zUrX>R-VN20Is2RIaj9U<_8`%EwdTLrAKb4Qf4X1cOyGWH1NSS|g2UHw#HbOU=CF=k z5fBSOnWSSBX~J*YB5{LcTfMci&G(69Sw8(5o9$Ipe8cSu+aR~qyzaiWYu57U3|(PV z0*oGR_GL07H}ocx@waK=WBFNz+3f{bwS{&01z z^I?Bf0mLTV=1a}5cI()rUgNwD5Th+ODKt%#$xnd~pDYXT$@12!Q(VJ@Ww9a@bXmg~ zV1DIFjD85*c3l))kZRbe-}_yL*pEi!x7m5fHeW*i&<(Xk0ZeWv{;_Ma@PwW|$SYTpQ&U`r0&ewRs%GA?tzKq8k+x zv$VOP`UYDM&1uVGogOeZbBIMU6L6Z>Zzaj8SVdjjo=)d@sF}l3Bg4Z0J+~at5Pjtp zt;-+h_~sZCbNkNlIxL-RC#PcHnG@Op6}$Kc*%sWc><#*+bWX}~UB|MW6U_0nQ-}H= zPJY_N&KzCG<|&n*K}Frbha$ox^AFt(yxhLj`x;^zASs^<6I6}pZt4reVPPFi;m~|Y zWqe7M{0L~p!!1Zp(XP=Q`m5u=Zx#5$(XrNDu%+q&eQ@CRnpR#nM${3R${7#?Ttehf zEop7Fu2IROXoSsNf}nZF%r?DwR4-gc7x}?SzN~S@X4sLW7vW zwbzBb*s)*uFaC{*ohF)PSJAcDCF$?w79zs!1Z((#S z?$$*IXP++uXbQ%<@l04AOW#x3$j5j|AmWp(Su?!pfTR#toc=blb*VHv>@odLd&mg6~R^iK!ZA$ z>>UZtFwWtni!|{_i#7-Hfrx!5Ct@%CFAM`Qxe*_5J z5xT4%YvlC+;C#hiL6vIUo8ea|eJj6jK_`o*HMZ$V?$j>Z3fR00EHYqQyr}!KL2t`5 zD4IVSte|30sCMmO_A<%svCCN$Fx(e**-XF8gh1)SGCZg-7j`@jwjwiftlXQAcqJX~%0{m5WwWn!)TV4acqy2H9yG*JWi@4c_KNT$CNE)Xwz%KJ=qij^)- z{f>l>z>dtEuZNHqk_&7upY{abZlKGMM|u@(AKs?{8aB{oKnKvUuIJ#iJU7|dzjUv) zf9hVR_Lqth5#@20^8F3bu^w-4GYr{}_8UjM@J8FME`<0>HuF<5Px;ohRSG0QTSlMj zsvrlPOK?%|m1l=nR7cD&u}ovwRQjgD=SOjU%KsiqavU(t$jZMadqu1S5BkD+~YsXiTw z(GcdKw(T_tr)H{_17~23SL)Cjtx5D#v7_H!TIiMuCc}>Ev;^< zi17Pa*z*NUkC|^+sbH9F{Xy_LW&;GTJ1$&)h4?gQJr!H!0Ufuhs>xG>R9t)Uue#y2 z-wrI>j+_6Dpv92X>#+ipcvMc~+6iDFu;49O<`#$1NhJyvBrew;KTlz|End*!=jn#1 zx;8WP5iIG<{}sII<70IYbspK)GsZAZd}_F|xGpH%BJ)2{ShMSd{U*eZD6HJ? zN&|jZRoE-W2Nd=oKw)G49fe(KOBRx57TUqcW19ZD$pBd#-BA$I!~6Ww3z!pv=1FpH zNFEfPSq@gG5($Jo#;~Pp7d@o!ViG$53H#!UceZX<+5GancKYG`8?5h=PS(Y!cZ^{W z1BTJb&I6eS0p|%jKImPW0_1wvXKYEwUnFdXk{!4kqiwJ}kOWBBd^rhwL7AP4t_LKn zi(Kz|5a?a`qP);ZWQi7^?m}HA$<@40-rdO9lOSS*(9S?TEqG_*ka6_3E7T0noe)>YWE7e4i)H@a^Hic4v+_e@n z=D#w}0L;paIb3NAtdwQ!jqk3HP^|nNU7zl>-+~wpCp$S{ZtG?WpLb1NsyN}vWNSrq zTO+D|FtWfpPoFtW$s62p#fODqmUxQu_MNSljt!HZvig*;!96K2yW9wVZ~{j_Vw=#R zN88EiyB#u%CLa?%$X(qoZZd+eBKe}hpVUl-eemqBZU@JXP`I*>>riP z2O;T}^mnZ{YE6k;MF>gA&5Ur3b%JXq5$T*5%`F50Ml)D4LqwRdKB`^MICZ)KwQJ_; zfJYzHu0I^9GiK*D&nDJX`01 zq}$=5uc4ol4a$pq)f;%pXssZpX`$Ow7u>SZI^7Ep*!)=`<;xJ*6+dOaWL?M%a%qD5 zYF-*SpCvg0rhl4)h}0xES(YEwT+Qwvf=$v*0I* zrKdXuQbw~1y5m^Bj{O{7gc5e*S7>&5%A~-UdPj+DKX2!EZLyPn6FDCsxMW|tD zKKWbgEKL?~eix z^^w$=6(c;h*e<775^F%sL>OLV1PXi+EJ1tf^;BERc77qo8&g0iZ2s2nP8De_o&*HS zLU}sMAJ>+#7vpp}l*AOL3JG;9rSqI0kZw-E6w$F^^Td8m-mNC<#S&Ywd!L!vb<6OX zhZV91s8@=Gn%L=TCo}tIXVQm~pQ_L2e|u>CuBwADhbw%YtUb1j7OToL&L=g<^K#VFGsOd^hXKCtE}TBG5=4y3?lS zWAxn;MIU51u)1>p$Lh+J;(K<*)2?BMGFQUwZs>imx^{oGx;mv!x*8Zb%$g7zrw^)& zTJp{sg$Q#wKT=-O#W#r3d+~Se!XKNa!V>1M+MS&>-CM98I2#^geYU3t#7wk(rC?+e zyH`U-z0(zUR>0lY9C#YfbUDgb@N!9ZN}0T%w5_I9RrGQ_<3@22+^j^)cN8T4)P)e8 z*$2+jX$FyKeso-sf0k3moY#2=T?JZ}mc99i#$KO%I|vHD8Pr8U`3@TGg;WepUl zBY^EW$F$RquX)pJ|6JkNUTi|`A#;%yt8=*7UBN88?L@kck**JzxEpY_sU|(zp;~EUp{&kBmD&3B5Nx2XimV`PDvt zH~+BaTy)A^80qo5-LKBTeaE#>{0_U$4|PDG{H1j?;Yn3bXb$cug@4xRdUDH$nA$R| zSR|Ncn68ok%YyU=?EJxpN4~6m+M_Iw{smPnf(Nl=2C$b5@`L2{6)5>Lw1-AYu%J-& z8IM7Wx=qx9(zWAHrR&IyTHx_pq^#VT7OBVC)S41H0POHMfTkWG0S3)ZEBcJZI zW?wYM&y5?-?MSyB9f}vVF!VG1nb47o77^$bd((wSH<+7H*rj2s1|Pg6GpPe0*jJ__ z7vuirM!53qpha-!sK!4qN2lAd-Y1=jg{abbg(j)$#jv3pS#B~7TGjWTsrGMx2LRsH z%}80wu3iIR%2UN-Uu;;tLaNkTar%4R=qtrE!H`&LOYQ4E?IBy7vJK2oLE<)5kO@g8 zu?r)a5h@6+xuw&%3hH~p^wPEsb4*jM+JPpSjL~kBu{~%Ao8RP-sgog+ znA8pBlXnZwld6cF-u0@b72^%yZ<9?_=MT#4x~9uPfPmA0?)&t}>T{xi04|JHKpN%}%Kj*WcuPD_V(GGGEbag)go)WK9Tx z(6#263U;p9su*#$(7LJyvy@Q5?^s{^(5}HpLo_+`$8cTs*q(S%;_kfsaIST@9mX3_r47{wBkK)` zMmAdxK~Ig$UHv8xJJC(U`l{vI1PMbn)*(*~%+)L}gLL0Wvq=^C%J!jqvg(PcJGe}~ z=pRqcYovWbt8Jax2)<3z9Pl8EBmWQ#Dh)GrLQiWRN_`t4_7Re%Z!inaV zAEU1YCy2UFkUbJiP0d1FE$XiE+X8J4K}Dl`>`tUhJF_DboyR;VEB{z&4`X${_@Hxj zgHSylr zmU!CQ&l#KlEJyXg=SL6f1e2%u+r<;17r*$9cN0Y%3u{G!;jc{&953?0fC)4!X7KFo zDNm-A97w;uJZ~A@Y;3oohJ*&UW2nQiB%w25#}IhH<93|*`wTMe8tP?XkdD z-?0ex`n)T?mb&ZD`pM9Lbi-|{2exi_d3>oGOTTbJcyq81ReuWq0!ZrZoquU4|E zE;_ZapFgg!$Gk!_JbBV;;2s@&XZ-2KNKVR@y#1RyYvS1C5Z-0eE{e5opaj`;^-=0P zxEe3go*m={b5QXbyT?y~_Hw9eKB!#X^u5CU|H?~;EjMloFOyiNsUXv237@K5Pi0hz zxTwve*A>&Sho`}xw~PlflX6w?Rhj6cH8kL zy&!LNeQE}|{7;iBf3?B&)Ft;hf+bd7tw#pmv`?&NKA|$EoZer?_qcWFW8Jy2&hK7m ztKp`svWQN$PP#ix9ejy57}N&Xcd;!pt{iw=cg|Tx(7Fn&*gsWXV_cT1%KA$He-O7_EmAHK+dHDt84YWg7_4h7@rSK|3U;w^pMSBMKANwxXfd2w-=m^8e` zmBc}hD|r*{J2P%lcRJojf?@?tH-d$*<8zQ~A@M=cLm*v7JsGeB}#S-yV$hqi^2a*gXD z`#XJEn|jj^;0=WI;1?Dl_zdYf$LXhpqgkTH`2Glzn|2&5fmTr=Ma`@Ja>SSaG#+x* zO3@IT-0VSrdEuyYMj%x; zqJ_|(V;Gru-v21L8nZp{6&(KNJ;^$Ju8Yt?WS6T3Cj^26qWz&y>qC0Zx$kQf*Q=O* z@3)hQ5iI;JuujuKa2O#?(TE2mJ>_z(!sAc_|8KqD)i5*fVuyCJ0CU3kr#DLVl=m5N zkWXDIN53H@IoZr^7SHq+GA_WAI8R$0)Kh9p3-8e7n{ABmKs!~a@!fwPT!h9xJkmZ6fQZnb72xH>G zVo=MnQ{|UeSs+w#cb~z&FFkx&cDfQlQbFo%UI2iPnjLGXS&21@3dKd~WTE2_8H&f) zDAevW?vj9$oPu5fK~+1Me$lj3QJ1SiVZju_b!P8mxw}hHXi^lwcSLRYPSkz^bYG-T z8_hNiXk2gprE$f`HLf(;|7cuGe-5~oE!ViZ0gY>+59%S6%Esi{Tq@&wI}EfMCK;;EeQi0`m3OPw$;{>)bC?9zLcy{K9nvh0LB@dkKnf-2{YUj=m)I>P`>EDDX zeGcOAOXmc-X2v8{sO1kx;`|ZBy$`wnBEWx5y@sxH`EK?m6wQClL{#X)6Kvw`ksz8L zmRnp&CxOM4BDc6s82@Q;h086j(%LanM@C`)9L6u0{`|GGzs78DOo*=<`bzV5B-v^H zL5fZe6ve$db;5J<%+ON2CT%L103v47%!5a>s-A&Y6U$7fsKd}k4=CqAL&U-qmVD~1 zxfETeZ{R~Foh@`D+lke0f@pPZwteGeG78H#Di3^{rFsNe>4{3rn&g+vpsw~L zmV+F!8>eKB8kzF_vCqlPDbRM7L@2$sl(tf{%JoyRfFyJaHS(C<@{N_z9@)e1`lXUu zL8GEP^dBof-;0ImPA9(j0O{odfzLot!UO8Vo?-u325>71rSc%azXHKme2Gd{C%ofQmHoM zpfR{f!(C#+?#@TQJSA*#qH_N@ci8dX*D5q&?eKq2RQz50d6qTj zKYLN$nayBY4+>WGfrxAV7hi&6fC*L#``FTVYrmbcnEX*i+DfU$6VFszo9c@oM@uu*j*rte6-%N4&|9}n4w zn?RXDuDN1n`zn>b?kt+xVYC|0^D-sxMz(M$t18}#ms`(Ze2bjSu0`7O_Tys1l*_MD zSU1l)#xzQABMvbsf?`6Dvta0`*vMtp2isaj-gj?D74l1-&tEwu9Ewj3!`8$VKQHp1-9pdpA{esUGMjSNGd z+6iO)k`}3(yN_YLqMq$_f<=N&&_kN!7TnEgh5%^>9T~>OLg)i75%-8XSqY$kw;5N( z*Hd4QZtHw4-IPaIrlXw8RC)Q<5CLCw3c)o=D@zd9z8`hDLwrPVPRhwx3wGbP4rrNO zhw8>`WCOHp11E06jv8&`=@aX(p1;o=&EuH_%UbUwb?D_3k2peN07wjtJ$Z;iY`KWT zUKl?xSlB;sujZ1)5@oMuL|Ypp;5*8;dc`u+e_o!W}27GQmq)qP4VPzQX7RS1RC+WJbDP9sR=v zO8Qgade{0t1+MM!y9GIw3qMBkEsJ=0f1vH6U?l_b}<5?{8}!eG}m!aHuJ3`4-GeHohuVn3YBZ?@4UbCV&e-SIGBHb<5AD`hUweJZS(BGMnbs6G*XecA<;tb4 zJ#Dw|NHPAL;su}m{4O0lFQbXJFq17yt{-fYHh)WHKoRxjX4ht|E4?b|_ltC0m9ub| z)E2uH?1nf9l=RR_ph(FYK!dm9cyJFA&dYY`vh ztvYgfYe9Mu27y{y z713G|6q!YRTM}>wt_W6A|mr7fyf3DEC^wq2}2k{AOuLld&PFY z&;NaN|CjwBUtGAB_qucCI*;=>eg~=SP1BVm8N3zA0=}QS%wLEBiP2MR(0sw9fw`%f z-4tGv=VznRYrL6 zx2OgpYLH|KVzA!bOLhcI0^9<-)9hL8bjo#yuO=fbC}ywk`@^JO^D5xLolW<& zBf))6U^lfSsG=FD1#dujPEK?0sD5!DC+4?c%H^QlYtTOeiO* zq&h5q`sONxl~^_9h++_Zk=2~ky7|xQR>SOZhr)Xf1y8#aejW&FBX{I)8nYm>u<3P88=-lJP* zHQ`H>`9Uctst3mxj=#8junJ%UK-KJl+869+*=mqV>c+>>Lw~4q{CAEWs131@<$;a_ z3uLzhO~A4U`eoqLMC`;`6nN#UmX`Uz1?UMf7JGq~ZJiIcQy{k*V(l;_r_3JC#lY;| z#;fVF|3xAenZsk;UU@zjt^8qq6fAvbvDwJ)M+)~M`=klBH4 z`tF$@$_O8fYlk-vT;7BSitAq^7Ev4BjZSMWdA?v&qoBjn`E#hnOaz7k0S}D@7#l$U zRx^c2MN#4G`&iNP)zTxjhS&R%rky2lUqzl{?@2xXKi`vEt1x?&Bwp>PSLX+_nl7`! zFU0!@>l)o+qFZNEGa1GJm)9r5m0Px{4EW zO#sB@$K=Y+i{>S!n`$BVqg!sKA`cdJSi+-xiZvYq3BGz#PD_)HEm1k@TU!gsTimOw z@t8ykX7*af`noEuPiIQUtE}YtGij;mp1IP;?;_7GpCy0r7;1ZWg5Wc8_c*U{i z=(QS@jV+w=6_p4Cnz+`1{PLxQGoMzOXZvNTl*bZ!tpSt8s)WBPYFHZeU%ASYj(31t zD>{A|pnm{-XwC#4tMvLcUNP7+cahA(Lu};YQe8J!JvtG?rgr2N&_Nc5l^qJa4IWA{(HyLy>` ztLwg-m59w7p?nYqWO&OCRuR#{m^{Pnj{12Z7kBc8#CddamB4ygD4R2RjTu|e@jnoR z6lAdI#Yh61(0De}{CS~M%p%=V3G1tw=$LRa&I*HIqrkeb5V$UbPda8wJDEzE%csV} zDF0yrJa7HCdDjZ{a)xCE*1xU!u|2;lNp6Av{>Q?<~{I>`kWMVAKLS^dYDonpxI$j*(zk98NUL3v(-b;{aW4@^_NN`)P_>;^27f=ES-{&q-^;F?;u5m_)Hn*Ft+ndKSuDV}Vwqr>tTWXG5Mj8?((`ETBJ*DOhli!1jLWj5?KOP* zhLR`p+|iMRn_Gi6bVKj{gXF3j`*L9nj8F)S)KiXNAs{|L*uc3XFl={_`Vk1SYGm%8 z=%O!#?OQ4o3@1iYDA?!-BAmV_T=10HwM7rr$xT7Oz6JLwWa&ge$b1JTViVrS+V*^H zw+F50>P1pv6=`-4r%Zi>ex79J1ITC(>RnlLSWmI%KC9{zwDgQ8PJS425_Z1(j*Q;g zcL@8l@c!)BN$R}nZ>Qfh4i#o^t7GP9usR>$a`#e@n#~Pv=n#+FwVhr5ubC9EOe7p!0HWdJ{V}r4 zI@56{1V*enWFlFtV@wB4xcvhcwU_Rp?%|a`@#Dz9!7HOzfFy_*WgE=5sFuEP)ZSsY zV7GM9>N8J<_SpcjAJlVEJ2|@<+9IFTlQ0b+ELLpBskk$BN~UnLO}w{7Bev_bJjdvl zMUNaRm4s{U6)38^a=4HxI!QtLNb093QH!G(qi`IJGJ_-98Hull*r-!E%2?s{JqbtJ z+L!te;SZPz$b0;Ot=MId&E)ogD9S0NI`)Gx3^1+%Aj@--$-U+0_#Q2;^@bG;U*bHy zQ*=L_F!_}EFe$Qa2J7LnTtr#H6c*G+KdaZtVNt*?01y3(yYiyz=RV;#e+c;B{LuiJ zG^*f#`Jomtut{Fp-Q9s`=nk z6KsHTHSa#$>#^Fss@#?R`#al%GA!s^Yi^&(`sthkpJ>4qb|-f38q#LAu}6k(r7-ys z&O8uB$(v#~@5pZH6?QQ99QchhLOqnK2A5}B9_(PkcZK^bSO&sSrj{VHZdG9kyCh0) zf0xyHe;pQ>X<{gCJWa`Jq%q@N@4eenAr)mLyo2WPg*gLOE;B`cYE_F`i<_En0;?3y ztaec>d{1t@5F;E9KkbYvwf#5_;lsAyBOFV@pvO|WJ8oi6*2J;PXDx-dbd>pXInTdOiCV(7u+qjrlm<;fWlPj|^ajY||k)7BN zP+}i5ufUkAWtzm8Yxps!l02g}8{S9|aT z4S%{Nn%LND@X9R+YI9>-HrjQWaX(oeinqMyU|s)Gl~&1|_)D5fIBWYHte}OltkTC! z&?>^io_X}YXMoZu;M>b>3REy+&j;M57{N-*qR?eFY5(J#{BZvI53BKtx$*)+)DU4L z!&ZUAQ&1wcj{}as2o~8*fy}%*ZcRvV;n*hE{<}}kl!_<{N)f1V)R!8)9rA~967=N< z^=?(jg_aFOmVHWeOLfOe!2Ul+lF7|5X85yIRlQXW*4WCf__c}l0=0_Ox50Zl&tcZ> zPeixYAI+-l&~$_`)@`zkSJNMMeIA~Ey8~&u)v?rWd2(~Cn(pg|@kCCOe|>=nr$1r! z9L?RkH(ZXkw~^c!UL>#SJqa+XNu&0C=P7sGl`TSm`p+R$d=dH9pn!2d0a-ov5X9@x z0ER^@2`E%7wZaU646r!nfv!CWJDxMt-T-;x&eipG9C%mw==w*{&86RL7Oj}VH&LZe zGM$;au3*BF8ToYFB8!(K&#srEJ}pVvzWJ4j3$*62hvdjjOLDYz>Eik*KIqOoa9P)X zE$%jHh#br2E=4{8^;fS`ief`>?kx53@0 zMC{BJU*p(2m6K1KZ>4RagAHuLWmYmM6>xM$yAKquL_QcS+dN&=6(~M=*`~7$6+Tme zEk;SRW=}tv^!!q@>SwD{L(JXUEm`|EA95+A_uqK(S$%8wPM~L4x!fS+EnDFYsLD3q z-e#PKWJc4^0h|*A#N$d(4!b&STdzjJ3VKgAW!3Kx?p9i>Z9EENcP#Gc-4C}2O*9qy zL1$$5fORX`OPl>`m?UmrLQuv9iq^-E+4qvQ7NT!Wv@)uBQ}&x({}>>MuL4xzh*PiG zqf@Kzg2Jt3_bYJaZ&AL&??bW$IMb!NqBWjIy!lJ|G>OFTX^K+|j%YxPT`VN=semR( zTY0f}F?#~5b{Orl8NPUBPv`I*Ku4;!*7o-pp<+?2#9$%oXtax9(m&e8+H3S61V58D z3;cmJXA&{1UQkVLO;o-T6=lWPyO$SS>1}SvO>%ehu7=TP(Q{{voaE zqK&L{LWeyzm5!7yX#Y${i(49|fd%{3N_Diuzo|@%u3cI-{)>uttn*f;s%U>0usHO7 zeC$O@+#$rm>sG2X-tA)r<$zW@A$wQVsZvmnrwSl;aW%+ux30&qJySNw|7XH zsLs8CbIGm@cj_B=O2)B4ISt@_F%rCSA8 zIw{B~%v)Utm{5ASG29l|Qlt|_@lmV^gT^e5hJ=IR1_Va=%)9BXwd-&7FC9rHEni5O zzKOR-cS)LoDFAP^AH1CzDRGO_HLh!oF2r*mU_UBnz>)g+eYBzt6#?eZ5nW(c74WU? zWPVHkPxM=YIuf4-{_krWwX&4&C5mKI8g@Byg0jW?>o{c8gmxdLfFlE16TkHoPA3ij z2>qEJ9~Ba*EtPD(XjM%eeNz7fj%vi5b(JF8skCxyGp@*L{=FMxJt){9##9OvD7lvb4iB5YvsSSBbRyINQ)b1bju=b zxA;&EgQC1+Vq}1igmDF<-pn738{_t^{7`dT7`5%)3&mp}6pw2}YypDj3Lj)t`cP95 z3-7v)%|9~vm+PlP6KGxYkwJ)xs%7cVd=N+5bP%k!n8WL6~Ndx;rrw;(uT3dd+Kb$NKfBpYpCUe6i!;{=8~d9 zc4j?27CpnNW*Fd1I%Do^{8EYa@5zg#HAfnTcf%DueI1wwK64tuwtqDdkh}f9uFw48 zgjCgc8b)CM6r@-O)3csf<88yZy&d&OuhD&&jW)^4v*}^gXuPE*f3hXFFv=hI%2>MQ z7L@-ADtee}?C_1y^p(k^_D^;3HKv`~e-!ltf?`+Pp@bS5>t0RwXWAdUir)?a-C1@W z1(0y}6cP-iCf9%5ieIky2Z2dBK&sVtCZnsu=kw3gt-&^$TQ^_u{fY_qy&>IhWBuM? zUkLOIZ+4L|D^d}d{8n=vwHLqx4$a~_w2iXes^~qgWf=;!O2aK=tmMK|XXA!79KvQ< zIK{gb6?Gr;CZY8l%i!d_?$0h$$6h9^!V;opKpT!JX_?-gPRAKfgYPjEFR9())xG2- z;}WUaQ~)K@D@fy3&(~5O5>xavvLPst?0(DgU{`%(cOOq@aiqZ@cg9{qQ875SDxZtqz{Og{kSqW_#-SxsVbS*tI83Cxaw=(9P@nCkxU+nmL zX)F$ZzV1xSQf>1$zm0#;iT&(2;C#;|gOLCFv7pgTi`tNIVON68M8W4Z^XnSe&4V4~ z|KK^-f)Rg4$q8)1PmRm&rhj`W323nG)56Iq7sS2NGvCzEZ8O(&O--Loa0!AlXnEDp z4%K&b6l%<_uV^H>bZ-rD`gzdhC6mM-JWi6K3v|fHh9?=(#~|1U3$iH@X7nERKK=Duc`XrFRzi| zDuLT>kHPw3&|RAQM0yb~`jsm_OUq8^$i`eIWj8(fVpn$A&M+NHamJvS$lY;KpY9)x zmjHP2L9(wW@>0mmdc}JSY#2$Y#vagaz*hx!G~~byE-%s;UN;eNEpE@8+p;E!g6{*ND4|a)|Sv*G~_@#MM)NDCI`ky zc(WuY`W|bM+qO{gKsuf5jDBW;Bh9!kT*}&dO+7EIcVx0}sjv0{XMwH-tKTJfsgA;x z$&2kRyL7u8)w%-Uy}22Cp+X^6?%V7gB1E2~pCYBb+3m}6Upw++Rs*TUNV_vrD_!J;dr78q{JkcyayKO|0Q2ufy)CvKIcUgXFPSd`sx zBwmQRN@A(VJvyOgVLVbvWs={6THm$;2W+f1aKIwi^?p=IlLK(T4mkARh!RaDTya@U zdR!ySf#IHyTQ78{-+}slGtJu7rm4T3j>h}#YB>-Q!{gs)9)+;3^*5vHmtLs9cfbZS zMh+dhTD%Gkf&?@Me;o)Nq|U%64CF#XQqNFkzRabRoBhN-SSVz~v%EfEUD~TP?6JV^ z3NT}NP(^O5cKdiwTW@JQsuWNC5W^F$xHr;RzymTv0!PgFLhB!x*o%D2I+!A+QNhL% zmNxqTg7{P%)I3{ZCoJb~+#VK`c8;Wtr$v1y<`w^vM}CzP z7&e)7W&2V$sUMfa<{GGZ7aJSe$M}>@wq6vU1b60H>lMp^qV%hewFzhBhy|+;dHd#^ zRF`*~4#Y)b6nnI4(8n=N*%UhzR16sDo)|Puby?y;{6JRw|$h zgs!3CtH3rOsaUVsSp0cka>=s%*q@pCuAd~$TulV$bmeG+0vzEU)fF`Jeho|62ssUK zHdMLSW*d_Q9OK?}hnC7mGEQqX;Ity`_rK?~W`?~fg1u^Qc6a%t(BicE%E1iVa+dJHph)TD^&K(3PJsy5AKANtW=xFMOFoQTO7#E`R6}bNbB&ukNLZWF_OgcGfg`0+Q@-Boq9jTY% zVLK+%&zQZc$%MfHrd2Jhh%zy?w@c=KKS4xs9eo~IQGnr@g+9UJ!5`6^om`-ae zI|cEpULOYj*Q{hc<;3Eqci%<(?GzTjYFl`!>tBr*xJ{WsQq`MpUdVoj>NtsQNN6$d zuvYR(!_UxrVzxkI)N?6oV!T_6%Ba(#l-zg;-9P|Chp*vKglX!8 zN>~xQn0~+ckF0(s;%Q)-xV}%5lwVtkCxQLd##&gS$Up2ug7CBEF7Uf4h)~5NJodkDwm#@s z&T>GK^(rElfc-TExH9wyTyagAl1X<4-DdX2Tz7obt3kQuj8a=&&8ut|=f2c(?q~tI zdboxbd*?q|mHPk9Uq~+~2f(+c#SEh>_*bTWog;{cMPsq@clREf8IX>rng*>Yym@SS zivCGoSM%!f)%mv*-cn46f$N=+tHA!6FSEZEuFLGN=rqoM?5{TLZnKDxKSr5XZEEd} z%oG`BhKHdeFuh)0{daoPItiY9Bg6_j(>1ZECU`9PRD#uJxE5cT7&=QOzl##+w3RKL z>eA0DyK5f5&e?cjBhp~|sa_Vgv&lU|Ch@7ds8HF`%XF0M(4wTS77Vq&O;zzzegO6R zvi_zX+D8>~B4#GSSIFs3XCJMMZsX%m@bcnza^5VvQ+dywjPWxZrkPh)d>Tioe_cQR zoS@g0rg2Q=o=rHToI26X)&}?>1JU1px9Fm2j~ET(3jP-#*~`dX%N&fcM!gwo&4b(x zw*~96fK|EX=d+ar{RYWn?(t#x*qT-?ld2AfH=jqB(I{%EF zXuo}MsLKxa8V4419V%A2c%@z00^b_8;6~YYa_ozce8(CKOp4`T<_cj+>2B49=MGSd zMWiN*v8^9>8e$5s2=1sQwVqSUrmeh2cX+LFIV176kEt?HlMH=M$J2`!2+CzGTWC8hJDl>E0Rkh=kv;Ne`M(rRJ zk%6bxSj^le1y%~nU}YUgmf+!gW6q5+2z@;&^?k7j!XbXVtHwyF_RCslBYaMV<#FaU zRWai?0|L%f*0~ zh4`r_rwZ<4QxuFkzf!Ctoz#>-@YUCDIy@(rR#a8pnkI;EhQ<8!Q5HU^%OG{dJS+i` zZDMIj^sdDx=vac~#{6W#CkeG;_UC;QHx;>DtaA`TMA6Fprmx52cThm)KXYQg@fqN2 zqBz!KM}6jE9S5Q{x0rp#bBhe5Y|%e)YGw9oM3*xH;IE4Oa_#ujVFDUz$dzZn_FN!Mms&QAq-O6p%WoQ!k*w!fU3xXg1#2fR20WYz@j=m{E= z6$Z|NZ|(=(h{LPvwm3b_?MDRI4;_%I^Nu<3V8H(Rlh#9W<{LBbrpUI^BQGtrg{%QxcnBS(yADA@f7IE!)xo}(L)4E$;=^!gmQzvRI z8KfJfSM8Y-{!zheH2jEsqwrq7$tIx@6(W+L2pzNh^V9`i*udii>L;E9vK}nF$MoNn zR`8x4l#K)S|F8Ykw7%+Z`)m4N_ScRfAx*#2o`Orf@Bb_J_%#KP`*FXa9niArWU~iu z;DF5j3Y%o4C$KJ(u?=kKCOlr-?D%;UoY_R{tc+Wlwj2)_u7+@c~)e{R-UkHA|Fjt7)hc*wh3q+!TnB3(;TjLAi5 zA;Fqqudgt5HkkHp1)s{9*p|Jc<8?xst8Twk5J^p9C%cYqfW8LL94c679qTsLS-Aq> zg7oNm-fBa4k*@ztfsJR_hopg^>oTsGWGbwz(At?Vc2<~520!S5EWej{b#rm_*k)+cd z7wD%ctDmv`)xz1YZw;9R7SOG^=;N|mK|_F-nGY@U>jw|n*D1PVN_MKoj5xX_ykeO* z-ulAF;mt*oHg~6Tu~kC!g4xh($Qvmq5!3J;V!3UZ4vHKSc8Gk@<-vm9Q}L^=$q!WS zMfi?12~uz37P#B$NMlK_cx{0_Ag3n zl(_3}N~_O@HkprH5B?uY>)P;K#2?w*IyjFA!Nq|m%k|zMxFgQ9shggeeWCWN*Jw9E zsEjX&6e;w-r?lo(U(dE;JYa2hg}{RoxjPlJx9D%zEuOSP0B+6ddrGU%?CAaHO-9$2 zPsnKxdVZX zjSfhQlDmf&K2MBTY|;9fF1;NeCDw0|H0i^2ZG2D`p*PMkG~)EUNqY1e>pqG#l`{@l zTr9R+^2)UW_4=E)XFvisEmb<9T|a#@D2-30cHj>HBb-^Mo}#NTvbcTt+P&o%jn_Lr z(8`qEwSe971{4@!0IMkd@z;Sd8{?v(8!>FO>$#Fod%C+oD5i>N5{(0`1LFPQ2S^^G zmCVV*+%mk2F;*EWH*8G^XfgPDjW#@5Cbk}o2zlBnmtrR0*ox$9%p5^Rx!!YK*L>!j zX{OlWQmHkPgn6unT%cRVqd3+jD-LPlU;=Ay$D-HL9aWF?yRYjq2ed=+>GRRKp5JVZ zzSGi>^tjYwWdIt6`0AMrG4uxE#mAy-p#4OOR_uKE+ z>zT;eI@4lE6aq@C*>9HI9vsY7NB?}vvlajS!j7F?QH&QW2(?NYcu8%6ZS(Q`BFJhC z4kFh{0>OAtc(>Ze99sVN;C8gaZxC^%)7NfSDZ0LbSTOT6*@1}CJvVH9KW&c9to2YZ zlFhHcp6NWgcYQs0_0=}=_|=^X+4`zNL>!6rZ!&hHTabmq`)GiY;KaS1RW^9?u;sw; zb_rFP7#6~tkIc|nK&-`2anc3)xC=9p;o^=VglGv8W^0M}!~6R5+d7yshcH2v^v}1tEE3(|Z$o7%dhfe7AHYaYUV$NF+33fYD1QO+SXUtTKk^ z3yK{d_!wQ;l9xgX@>ay~d4YjtyBu1wO(yt-Xv|izcLB! zj5s?onM1My%i9A=_9?*(9|}8XP&!8OsDHU^NkYDMdwGhvLp152=d&~nIIVoBDABI1 z_5NAHSTIqLG;W_i?xyV(2_FSP7<}$GpjK>O&2fMuNmcSdMU+x~Z+>_U=t`{}&J66V zd3!^CJL= z95psmPK@lJ%}r>>v>>SosrNTWchq6^cmql(<8`&=(vliJP6~BqojPu_!y|{&7stxM zDTMk|?Hkbud~K!1y`pFVL3ZqK#JMHkA@Fci?7_g&5`xcc0>qni8xynCECvV86||Ui zI3{d_b}H^&l&EYgZ|*t&nRgK+c(K-kvh6}9R{ySzZS^&98q`SZe(&vN^sm)r%+fwa zzTN}ws)tG7DISSfdYAtAD>cvW`4csE*eR!OXrWKI#;ubf2LBRQoehL&W`miq z<+Ce%1e(42tZ0Nemw9G^;vv#=rNi(eeY*96^+Y89yt6IcgOdo9=n)N<5q0)-)-~W3 zvI1Xb57V0mx;F{QpP|bQZRq6a{LCS){TpTw8Z@f3B^Ae)@!oM=M+&!Y^4u-j*OIe; zx~?ysG&gXkUioImY8&rYYhU4M2YQX=_fGnm4wXcg8`=rqaeDm=QnRDT_uY+!ji>72 z3nxh{V^#Orw=$g3icS;f7?UMZC}yMV?ndr?E>c5~07y-PDPi|4X;&1UdCtBB9W4hw z0>A3IDeDpAH`NyDLhiy=+f8djP^e9jOQM;_Vb&(_<5a0H`JdeU1LF4Bf;3TKIWx{P zM<%9_ZnGO3%%q4#R$r{4&FeO0dles}`hARD6Qv`gXGa-7GTp`QonC4~9q8lCh%iB4 zx+BEprZyw0Mfo8HyE{D1j+@driEW6FfJ`>x!ZCo;DxRb=+TeQh4eu3a+vOxvts3(- zu9WAgu3O`kW$~3E>;|$t^{KZe4;qC+5Y<34+`ZL-t@v4o{-rWYi-xEryTs8)+qD$* zh4AUOSm-m!EI!Iuh>M=qu0INkRv)20&Bh(LA!+zeOQ@2mutY3xcs60B4ug`d7W>9++Zp=>WFL}vfmk#$Z%-H5!!6V8S z(c9L~C*WV9aga&QQs#^s*7j8-C|JbXJGP*CPtYc|lVbxN?b?uQ>8~xY<87QojRk^1 zJwdELvNs_@Ffpv@Kk9%`!iNd2eTOi=09s2|`wRk-FYX>7tetL$h7uB^-KrLJom0YG zp9epfw|<$)^owy}9We^V1x<%|1D6(1R>fDY_I0n-&;p4Y!1KyRm7>%BJEj$kr+;Bu z*QN^rru83Brvp`rn6$rkenhCgXG(Lfq)_==8*;Oq#nkISMWIh=7 z3cr0WrU29^;vUs}CGhqLQLDe`6fki#Wn`E$!)&Zm56p;g@rvYFcarNR_A#>);Olx1 zJV&b>e_1U#V*7g0Z|s|-WY?Lt`l3h(x&A=`89Z`?lES`DdbPth)PXojtHJi{<_Ba2 zc#v0Q47C|pS8>PtvPpNJDLDm_%C&MAr++|wtn+&2eV1#@3Xr87?tw|)L>3^b43g@G z7BsVqa38JO6~48*J&L^q!{rHop@!M|i7=n+pu>44%k;=sIk0(o zv^h`%NVC2xeQT~7>#*>RK1`n0a@%ufGV*0v$z3GJ^P8`#k6tn|f}pq$DLqJSC%w)E zxef=b{IG@W>5d_L9@`@tmx4|iRr0><;`e9VusTDkc7sEy7PXwon+w31crEgrppxfE zuEdX1W$EJcCKqC8VI1-@S2wR!LO>BVu;A5_hcHB&Hz=#UbC52i3zc4xXQ zd#;FHHckw6tZM|O*HE#$s3X<%p7m$gFWbrzxo$B&eUPwrH$KKO#bHI&WTIOWZbN4P zOsf!JTFc4rA~y+@SEqUJl1}H3!=h2THd-tHzNLOl&u3~rk`6qtKupG;#6FH+&c{90 z4m}f_P)9mprdB6k`iA)ga)GbTnW(f*I5!|BY@Zp@+F>JHP4F4i`MoMX0sgkpPt7n= zO7fL$y^~HD`Iv;xXkx3e49niu`god;Kv(!7mTU zqTR4Iosy-ON*;G5)Nejern*RA$9$+8K*kdAx?|X6rNDwg=K@W~k6E$*_f@tOwmAYO z_Ceg0aj(GXxvCqJQwJ=ApoEPo&mOH0o!aZo>nf*MFV;oS1y_r)=m0gT9C10h?;$A>JqJt;8M6wFL~Eey7ze zx+`xFQSM>-=>7Qe)!3v1OLj4mv0(jaA@=e1>!hAeIs`RXV1I#^Xc*aPxA*Rjr7muj zpFx+I`l!S;y{g`@Qw;d*TZ+3NG(Z--BqH$R_F1mRcb~et{4C$=_J?bgf-UmW=#~Vz zXEjq3?R>@U(*7!dXIS~}jK_Y-Lix_QtdD#befX~o{IaQ6%P`GzXQA}b>+@ihAoIK` z1^q7bytZEgp4Zm@>v=^2&nupIGwp;5Ac{*O-4XR9J>6hVlR2a&ZkGrkP$Oxu#f4vw zp&3=t95b!jqZfEf7aJOHMr`+ao-R`#_ zG=ZG_jyT2&YilwXkg6nc=3fp>5pM)K?8d3$BaE%Ds1c|g!OkXyIf2Uy-VQB%>I7XH z4BRlzZ8CeX?ipD$OBCO|9OnJe2mF^zU00t?im^qV5-|b(F>2qfDptkP?N1w?)UO#_ ztMWix!B>7g4FB8m3KM@Z{+s-E-_4~Fb7bynnfBU{TXg6RZ`EjOqb8=BIPK*C^`NVT zy-hU*VGXfHs0sVqs`j-Od2Qw`bq77+m`&xu4kv`AF7Ej;vV_WnnX-$D{-nIKY3!k# zQ4^I?;{peB0)13;*WrkJ;vW`fZYZ>Ew%%XRU(d3{P?1(D;97+U4^WG8eQ$Y{c4A2H zEw3-P({W<=^r)rRzN8#jOoYmd2-FA_SYB1b+N**FZy)UCw^rrfY$aFPT`ZW2jxwS4 zyfM3)kB88xF}LFZr|mue0`PF1T zKwQ?o_}%{#uTn?6biH&SfrY>kS~dGd#%Qro19HlsBTrT=>|GtPhf)XGY+G}eVnS%t zw5|F4vkJlIV-Ib=9l4d-Y%Pa-Dab(B_^1YunzP6ZV0m>~r+pbW z=o-)=P!YA{Dy|&aD2wOU6L?@cHx2Z zS9La*>3nxrwK;096`Z2EbaU%5y340cP=W95?#@p)VytQxOXO#ZJZt$>6kCkbSGfqT zMQL`D&<3{L7B=6Y@sa=Dgk!x535YV{XA zIF>aM`8+9lZif6$+M&;uc3^$I3(UK$ib-uwDc)w3sUgX@^L3Biu!%#8w)QxGuiUqU zhxGmcQHnt$LEO`1#>T7_F_gJu7`@3=h@y2C<2keb0aENKx!2^s|ruNx+ zb~&}<&>-@e4eG`nS6;`&tWjcFLFLqEl3`f|oBaPkT46u_4QW-Pp8P z)asS>pN8K8G-Fk=jC0Gn_2I7dBUdO+cC80+Yc5OrXL;=HXspy`XFFJF!RWv~C9lF& z(k{QUGwu$S&!>-!cH=_=P9$IH>arp(i$F+D0w@@c6*bz$B+mh zt;9(VCliwr?zfXSbu4C`MISQ|xbb4nh<~ZZXw95?=RGT$Vzx} z01xp?Up+jj78*hGwz2}rdq?`#EGV3|HD|J{dp zt5Rby%0FDV3T6SV(cA<_(nk5#1`qCqs5hVX5EE;E{g36fhCg)ad=8Wt(*oMo&i=lB z&mYX8G4LON<@H;c<<*YshJP=W;-nl6MFe3Eu8RkXBm=}J3Q#V9Gn#0}$rVs*3?)w= zb7EM`C;d1Z{KM>`7VD0BtO-|RvYB@s<>D6=4=k^dw&<`~j2>V+9G_qnPdXPwG9ISq z1?AsMzG=K7Et=#}AlCvlA4HuTdD}lKI4L;VM~Lv-H}Iwp0>}I30!piD2z>@Vt#M1j z*HD56Fw%kL6&~K8Eu3cLoL0(~-%6aU-gX3CTm^R-<$92{GWi`7kJ7^N!1l6UFJoMK z=$P+7t`F69UU>%xVWC?;f3S8MvH^ULigh3GXZX+F(jrw_R<>l7pZ+*3C|V}xkHBS? z*MIV5^goo=W`T^-`uB#<3T*iPw!F@{b^mR7<-LvE69YR~=gR}GvS}7nJuc%IoGU-k zLyj9rlq4O&eiyp~R0TPs?p3*Bv(NEnb5E!SD2Gi{g|qF{Y$W3kFK47ll5*4@v5p!& zIuSkkvUhNR4oT4AFb>7{Ql)b3vy89oHC_7+jpvks)PwJ3UXx(n=#W4Of|A~ zWe>f#T{@BJ;FNHfcN4-Vtj!iu&K0$u8`Hp;bOAEn7E|}E=DNGhi*!>tvz2cxWAd5a z+gQ%~*M_lRSg!)=&3k~@jT%?0H|-5E^h32Tc#c1PAeNRkZVr?lP_#D&S|Du+{M5P0 zhD9$g|5=`3SzNI3&z5{Z-4627aV{!^9V!FI0{^ynb@4xf3NU9B1zT&s#t9MkNM5*C zwRV~-)U_l>ZW-b7T4V}L@`4ccD+WcM6rN@TdDXAd}h0G_e=}IGYjf#?!}(+5f&X`2h2ZK2i!(*M zlRlv+QNTKE2l|#Q@gm0_F{3X%xl??RN~_Cssbe4<1$Y5YkGNEJm%iTBZecE<*$wayDg+f3U-n z-a7Z|{DHlH7VqPLrQIN`r6*r85pn%r>0nJ<#8mOat-=o9BPj;)Jxl*Whp*#}F|J&J zM)NWg7=S}WzVCpaSCr`m0d2za*}4!WKmC6XM~Sr+Kg2@5Sk05RgJ!YMXy9`76F@jD zhF9BR_ho(B@hfW<$4|v%kt`qgxvt}<>a{EiVp!s^znG00_^a*+Jp0OLhHSps(zS;M z96Eg$wM9*vJ^e7gNVzDcv?QX_I_&{VUY&HZ*-jIy=K9<*1?h@3APRe4o_6j%Sz@#F zt<{z_9&@g&4gBvCXy@*2%R$rKmnIGp^O+H|!mM@O`R=BQA62TqkwbS8P71fKJc(cX zO?$qs(o|tKc@X}DKE^7S(5H&f%M0h(NW<5+l_G_foe^TG+-wr0pU7ytx9u(K4zWBYNcTFzjAF0y#0shD}2+X)@rUaC*rOV%C$CT|Ow_{!8hVRFO zo(;G++obR7@m9ub9R$2qSkCtMyw+BmF*iu>)J0>%N1pxe(*`Y8vdM`wm;=Q$9VvMd zS^u(|(@W7F{|W1?H=2qm-b0+1*YzRWgtJ1QW`sV)Y3uxUrS?YM=eN$MNcsrXzl^k8 z+|3f_1ezy0zD$qv(%OXrsoMR!sqP|B2nliT)S2EhA@$?&NDe!fOiAygS@+7va51cWRHmsdKWr8$pWo(7X-VPcAha(q2nMgyJ=ZdWGUUrF1O^)28XbjTDcaX2A4}Z?);x*zX zaT#%UxB?xR{=KM4YU4=-@7;~SVI4*Qn++-F*GLlFR$>iDg}LD3%e%QfoR*7cn1PUK zyrM*;E?mnvMMK-HJR)ryMoh3~2q!ShK}iC*V#}-3+1ijBCjeC(wyDO{p+8iZNFT!$ zb$q+o8%kVSZNz3n*U!gA?4&ajB2KInh~Q;)00(4mQ0zsZtEMJZV4v-s`>tOQeAanz!PB+&=!cj34dczP zAYU+R7AXA@rAyymMMLhN{FxJUKv5$T_TPa9kh zZx-rb!HdcF964ueB4P*Or>`yp_1aN}7Wjoh1dZa~MyOHTHs4s?EJVzcQnBE`+ffgD z%iWnQ_;P~2*jG(lOti~)juCg%vHYCK>sMnLQlVZ!u6ht$+)&xg24e=CSxk(JxW}!voonqp+kt<~5&f}KygkRt#xNBd9YC_QQzOP7Ed6D3 zX4Qm^h|2!r>yXc^J90fUO&c@kTk)thh30{RPJK1qRr2TXky~?RPZKgo{Z@WMOyB(p zCph?F3eXM`-bI1OE)li0Iu6dO8uc3HMijT#zxB-q)e58AjGonahxdQ}>;s8agF}%U z{2m9+gSf}7Ak0+HAFh*WT+qQ5oOY?(x^>;3nT7wr1ZW>uKTnEe5oYHrWC1H{9j{fw z4O7EdtNc2$8|b($v5Y^H9Wf%KwZ3kY(OQSv(@yAJcIclT$|ED+JXQoAoe}kb>5do1 zs2lDRpSh;$PCseKyo%f&u=LoXOlaPT0482IdIanNKu*Ka(qrA7;a-6x~9ibS6#jcRM^7iGNJpp>@M`V;$Ia5qMd z@(?OMF)lvpE;{rVB~O--W)6EB)xz-pUpy;LEK)L0Y-n693H?*C=nkYj$5GyyqS z`#J}lvi$=dN5W9j*X8IxKAH#uRT<0~bXzZoYoq&mQ5uo$@Wa)a8&^ZSK1pMhayJJG z?BfK2qC88On4RpjE%36*QBXcs9G18J-XB1~VjB#B$i>xKgZb*DoA);fsfZHxP4&F| z_3*9anZ0CyzH%!*)og`{NE__w*p;B|A`~SZq5k5GnShSuJ5q~_b=cOtA5^%RD@!GX zQtuw0d^@8@ffrmDQNld9h1&x_&v!^c;Xv5B{3m6?ofga2b;v~3i6p!bi8=`XD-0DZdFX zSr@UGaPkE)bG4gN6ZK-rSZFii#)wYeq})8{CuHYhSXD7~88@_{!&BEVK^FAQf%H zK|)8G9JmMBMI%_XYgNb;ohSP#NR-QZk+JQ2Jn&fa>%;!<&~rzT;E)rP!jx z^qG>d@zS9!)|{4iScG|{sa&K2M}0+@r-l-)S;=UvkTSmp=7LfrgOe=np@XC$nGu|$ zX|~=dv~qpaAK?-pxOGC+Z`i?+ni{yVis)o;j~Fe+0MbI?$xcAEe$2~A!IuKaAg9_} zC?4T;rxu5u%`UY0@GZ2olQG4JD@~5QN~$Cn+AT^KA5AO!CsM&|*)09MNuIC{wU$1@Bd-%P2-w8xBg!h z6f81HD?@;&SkY=hWC&qMR21w+L~AQSktu4_Fc^XiAqgTXC?SzjWk?_*RcJ*9DFQM> zNJKJ7!GO#VNSLP(5<-A;+r9Vm>}Tsfk3HwSIscDueBlc}?R8&S*IMiMUBBg71gu(i zAz`&{o}o3sWcpVJRL(~SFpB(5GI1mF4x}{BNgZDd?kQWG+|_{3JK}cR)xmOhD3S@K zBNpatfz8mfUQ98t77GKwz>6W37GwT#9?m_W96%_PLjSW{YsTN*S{+x$|KZm9X>$Po z!>x7sYPiE&uDD+_tR}9!4meqHVKmGv^BL-N%v=5SaYqYh17J}%9orogF;joKwVv{+ zJ8tOjhFX^wN3msKwPLxq0095Y{8nRd7z6*OTWit6ESrD+K`k!l{mv&u6nnN~COJ5I zX;Z737(AiPyJ!fk(6j8i(-^FQF;}fC*sQ^-JFe+wY(ubFqX$6>vW%%`UAM}V4?9E( z)qX}qA9ZqE(GsoZ|{iebR@s*qgCG+wBsJ<>3s6v5F!-?hO#X<($Rsw`ba3)Myp$=BIfmCL)`^Klc=Mv3R@L31%$%P#N-**no)AjeyPT+}|rKU>^8+4LBwE?0_dxW&a!fKYV$X zvXQ)rNWkKfH(G4ErS3K&F2cX(X|YJ3C@>0Y;oa@`FlDV|#-*+0We2B{9iia;?IoEg zmb*GP)_wIvDYiK01!^b1%JNI>CfEWKgg)mXk95xydo~>`^x3`P+*b#bG+g~OkLJDP zIBvys-aH5!%tXw&YmR$XLPHb-dafj(o_dr|@O&0XUK8&m)I$R?Q+R)c-*7yi7?SJ8 z4lpsMTfY;SYSfWOSSW|Eh0Kfry*ZH=?*O-9c>`i9aZXV8b7Nl~4t=Z}XLTG>k7M$NchUa}+lcggGNPMRQHJ=m^ zgQ$IAI>qN0ylVC;tF^`p2V|{XGw;~|K+#^O%adSd^BiNpR*mwX&l(4f*<7kGUefr* z*W`iTX*~B30-Z{J(b~zF>xM7VVjZm~C;-t)?Xz8w{W`j46D&k~;;xOL2hanng+P|$ z)D9V!=ecYeBzhNNw*+*GiY)}bD<^!m{N(+$q2a)ZVlt;H@y^LgKaKvFc#{oXG$1EC zln-6#-+BFxsyg@@iCz~e5Z*(%2aL_9@nVfu@mt1PlOgne7gLsQGe`-0Kz)MusAkYygD+Z-TXI03vnibu<&~gOz>-5kop39=RJyg7Vuz4 znvLrr)#qlm3A4If=(C-7>QK?+&qD@GSlFU=NE>Im*O=k`&6l|Qs@L_XxHUn4o7F0& zIHgYiP2CK?kohO9+V0mGbPSA{hotyv++6WuVEjJgs-JPy&$#MmT=g@q`WaXKjH~`H z`rl_<^dlenwP3BdVVf z)z66PXGHb?Bt&&#wIgZ?Rgo{=H|_N|#m`2bMdy>r8KFbxyLUb~Z@-~~`@7pWS8mU% zriU^)^Lw`Jz9E0Adh|IfBkalIwvxJ^XxrMJwEC#NF8R&|{0wAjS)?>#LO$=hV_VXJ z_F}*=q_IKmgvqp$R-O27OZg?eyb`*acR#JTx8fvweSCwnc5u9Q9VNk8Z9?{Z%Uz69 z3A&?}Y;I8xxqWimgA$2E`z3Ltsqqr&gyC!k^vo;d7GWw}bu8kWV*h=bTvW+<`LTH{D@cL><q0MM4GJZpT8Uh_1b72{fv^k#oLuYNF;lH4ZQChuUDSg9TflRGV9N>)3ek?$ zG(k_uwhMoM0>f@14mGrQkIkdNd`8?d2R(MyW9h`Vu%TLAOpv!T1JBPfw(~TIn>LK4 z*dP(vBD>R9E0X{;me~`(UifI}B(UvmTcLiO`c+NB3<8t&4H0g25ysIS`L&yG{r3#Nv%@#Tdmn5xB128h;clKfKw)EU-*7K=kUFxs#ijTFzW?R4*~et_78vB3@q51GY5j zF|eyv_4i`CoZ?aw77b&0v;^CzF9LR9d>Gqh53_Zzd-2l+w{h)fE!us_a16Vgge~Y8 zb@B~VC)~br2bGxEA}5V>KjFUXtncAHEsBv9Sz+MH`L2};}eCNgEK{2ByY1#;JVhc0)H|u0MvXAc?Y+w z-@-A$hTKyFVHw@*XYgqjt)p`02r>@`eYkzZhj;P$`&a=FP#WjxS%9&-A~H zZ141m{BXhp5?h8 z1}!{it&k$kao?P}Tfz4vEd#80jp#XxcBVm9pJ9kEb&@Ti(#iYVD!hh%DQ7qe+-XrX z!R&=^Da#6gU49IA_bmrE$kq4y7`l^Q;;y?mJ6eY|n`CER?E1()67r6#xsdtei5s?f zhts2`Zv9x!uYLXv_tSR6+SpmvScGySZw8Y}l*YOj+Zt*7HE$cccvu#7`eZ$Od&;Ak)fBc=46qPdnZC zT0d38G3=<0KrF~UJF__Jt<)@1vF6TTr!te8jn{z=*v3)FMCBtOy8v1eei<>|(A~+1>SI&B`l=5)*3p7lqI;(18hfGsiyC(ixs@e}e zHQzD%QOPRkYZKaaWH_)o${Cx~B|mgHClzH}R4m-RXCkQ#3T%&Vczx9qZ&>AnE!wG4 zBy312S=t7!Pd6xhV=a|BX@WJ|6RFF=6pyfaNI3Mt!|1!Z)o8i`fLVa)Pm{{;@%y8mt#&UfbzVi#z zV&E&^IRebYM}B#q=QMxEA%;MEXZVy;@&%!S4XOe z_$Wb~WqR7)Vu*?24^TL?ydpu|Lzmx?tzbvA^f-3YEH*D{t8ik#0Fh}h%BuVMesu9z zQ_Fih*NpIY0X`o_($bAF$tle7so|v8?gcLeyp>K9YWD2$`c8M>chyDjbbj<$zIgxB z%t+R5q?O6qLiQ0Rv0Zo~-U^mVoUJQX>0Yil<*vTBKyzG|*$9ooeN|=)*tvQ}8Mtck zWtWiofyYvub+}Vq_ikwT;Pr~$srlt+b&f7z1>6+vs$9lDy4&3s@P14HSD(7iSK7@l0?FH;yk?LU4v8aBH~QLC9tsa^bI$WNyi= zS%8qW>AyYGpweTQO@SQBv*7=okOf7~zb9mwS}3hLQh4Li4AB!7L$w>+FgP4S7m?`I8#5_R^LR;*~|H4L4b zWPY%k@6^qh_5bt&02GXk$`2s(&KbHMD~;L?F}DD>NWzNZx9~diU&`z@*R<&%P7j}X z{(pCU|LZ2lZNHjp`uJXo(~S8uMWi$elWKr4)9hoh8q0}XzKPf{BXK*s25!a^6<=JE zlScQmf=J~v*=da8RrZ~R6m2+OXkFczcbO0Pd!Hdj|(Lx;`-yf0`XFHeNo-S8^yIq#1 z0v9f*YQ^>tvQW?NsbO|JFji*RhNOmDkj$~_;;d}bgP_R5G?gl8Ok(p(XeO95w z1=EYB8z#Smq$0W#x%t?&LK*Iq%%uA!F@P)F1o%H3(*;W}m^lx&@T#Z2tMT(5oGmf7 zxoLffBuN9K=;HLar2)-#k_+JOcLCAc8ab=#c29c`e_Ec^eNg#@ z=tVnRlbFk^=o>$4XU~;-}IOW_)>4L-0)M)KpWHWu~@8CeA9IT|UziwDOK6$C|A^)E7Ap zh#$`?KTu&t+%p9%UeWN*(Gzghk6Dlf>8@+mK``x=bd4Q~#~#4#4G?7J*{!0?rLo^4 z-t!owt>}-q*A-o|YdhbkRReRfGFt&JDO|q6FwMj&ajR^r{14g< zbAOVF4a|U*;=uG5?N=eJSz5^IT(pO9tubxBKg=9tyHM6(=SeayjQuVf)~VmJtyc-V z{H_8<@=^^Gl4K|7Q2*u0u|UVgS&J#6*cC3EOBn6;i%y?Ed~46 zOv0N>{>Jn2w3L&}6E0>1k)x($$~*1UYIAnXFl>u?&D=K)S3+{RWy2?ba1osRVGsC? z=SSk|pRqKeheKV9hTNp#CM@4a36V!tLY%o{Nja{>^tb#kO3wceIpe=V=fC}}#?kB8 zE<;q!%$t`r2uu`LA&e&Ck1464W-qG_Ou(>=%p1!|E9+oSP>d9)n^_*Tm}i(#{wjeT znT8Ix>Z>+K2dGxFN40%_(MXAMnLc$UFQ;$cw}Y7?nwXe2t#<9JaVlW*3L|K;TP{QR zRa{)C7`HcE$}qGbR-{)Om$o!j9+MKfm7O=Ar6sv#H@MV_6E{hwsPP$kibN{aot>zT z0p|fWB36o~(M!k2*-OSj3Fam%%u{q4b06zABBe#GVnvo3*J8LdJLOb`A@Nb?ePn}> z_MPUscA2#ysT&@+=CCrJttyQ(8qLih*9Nk3SPLJqB+2-$|3r=LU|TkY6uyaUBg!QB z{a6^+IsF@Tujl{5c>aTMoOqw9_BvTJC;qjrvN_j*ug3+=^wZ#|Iel%RtYhzUFh$eu zrUR1)eKXJijdtcrc#(P5ZLW??&p7k)(e;JDGVnu(Sx4O%j{97AxP`2C-(Hol5EK5_ z$F~(+6D8@5TblACSf10~WvfsgVrrpDac+OG@EkMCHb1`6aQ0-kA$oG8L$6+4z*F4| zv0plaP3=4BQ#DIcEx+TE+t^)VM?KP=Akn`AOhMl&h|C@6tyGcv9e0t&)?lV$Z+|IH z?c4d4^K_k@InYdNrU5S$P)|jZp2A~>86#!(24A-aSw%(+RoU$?=xI`k{fK8yg_dm_ z=oUR{qE+CQlFhN)1CO~-(MMecg$AWeqn1ej=|28zvNl6BxfGL_O1u z!B>3C9q={#%y8P5dJm+wg0Alq9nynl!wXun8~V`R$;rh_9RX(BGA)`pQ1QEAF?mSDK(FNJ$);V zoBy)!(@UzE{t)qn7LI-Qv*j^YrDno0Z{qNex8I&$x|AcK*FHCV@Am4i;(dC_ z`~C;xTtRT);eXUr2V|0tB?qbtLmD`f(hM}~-vZ{pUeNzu78j(sj;2y$M}Az;bLqJw ziWu4ozH}7`qoRpX>wbr76VXiI8NVR&btVKQ#=ek?eR@m!h1*6F8*ZOyz%KXsSap@) zq_t_Q<mTkTIZ!V^5LOZk!tmhk!dqXDT;ky3hWjU4@ z;;*s>>)+j)YG&iR-HLF+#~$Mqj~%!CNv+N~NQ_XSx_fLh$1##@#rs$(hHdS_s^3ib zj{Sn=)Z`M*9--oO#5%R|b^yOnIkijn$7_{S$7etnU3yEvN7jEl5cEqdg4Y2reh|z) zv$lSG3iuLpZLeNuKj!tC#do1TDYn|D*Ulw;#Zq~NUVT)btXpGSHn%vNMtvQA#Wxc9 zB~ft(L$1Ugr&}(2#$etx=H(*sl`u%HIYFfUR|o zjFM{zARjyGJ>PcWFzZ&CE}j#YSlK37c~d0yoCfS(mlh{oAHuMcSntqRUf>GpFs(%{ zD-NUYKeB3O(NeJ~>I+4ga%`IQt?SGY>n90?m+P*Y1l=o(3^X)3RK1MLtI~E>Hrjr4 z@L3#(U~vYR9oNJT&XmI3w)4Aqr8UO+uBV!44F*%L8WTz&lSr>q&FEt(_>MQ*m}MRU zy&4Cg1YliWHZ63pex4t_@4^!3VmnXm<0srv4f9^rb)ezqEd@rm_5iuW)2EMY+lYUq zHQ0Yb(>Nl+Vb{QGTgRG(6iQNCs#d3a`d6VNjKXZ&^`|@$3g7-NY#8_%Z_&rD;rZmyFaUZWcav|N@Nq<1haDf@hA zO*ykl2YIYH@h!J#yvQ``VJSRDPiT{5`$+IyvsO=Hn2aK)DrH2~3ah*KRIMvEj=rgf zmlW@;p4UljwIj)V+jWf=yOnGNuj&XVqq$kDC#J`AAkzs5h8O9T7d;i(c$j4n_q~1g zcd4h&zepVRcR~3Hy{==EkuOKyP@S|GnB79ZXK?I1^AY5>1AF;4Y4o{sFkzX4QkUd$ zTu9I&6S)P8+u1#FryLzPBBh?l8;CcD@xu*&3-8vEmrr>xbr4exmnEi!Brf3jx*Yqs zuj6(2o)4Di*k{yc8UKnOD{|TLyXbvkI+!dV+{m7V9jv+M|6|^#=>k{xt!p+vZJ5)x z>KNb~NjMOtFtFv0VTE+HtlhCtoLrAKP3gGoJ75TZWR8_EuI{#Zj&O1;uOw|VC#u@a zj~KT2<-pfCN?P>edTGd)2^Xfk6C2$zHNwO2_G_F=ggGq~VXn1!pC}zWF&;O*U0#?f z{k_C{>27NxgEO)8&}CPUM(CI65UU3X8dRc8k8;itBTtKaLSDu*I(FRPKus`S!ceQ} zN+3H0+fDH4;uAg=Drl-(d<&~($84FNm*DpH`O| z(rU9{BFD(t`R7u#J#@=x^R2Bq@7pG(%p*#-mzAu}b=<3a<%tga*K{vP# z%zlaRbnL?{nB0Rnp=g3X#-NWWn_(NSkc?=ur^J>Q1MrqBzSJrHJU^8Xq}~fk3sUJh(%M0#wCWrL&@)d;wB@I{PllC`JPh6ayyHK zn_yV(Vz$ernVD|59bdL>WESP{8SOHb>{_&9NI71$^t<$cV^kXQ zRUGHcg2{=L-t~c`p-@e+qlV;p^xPSi1D_?#BxPVv(h-6gzvHwQ7LMM>LMtVczZ4UC zm9YsY+7btO-PSe`Yl@6RHBA{zWJ?N*Y#`WlhgS#p;(!)ytUn<@wpPVxg)yhzdfU4t zt^}({O^$=A@4~kdzPTF~5(Ov8c_rQEcFRqiBgPW`#lvjrV<*R$3z6sBc7+aPS-RGh zREPFo`1Ysa4}R)hX|)U2q;F?mE=>U1)RoJ=?*cL-0i7z+-CHpjAsBo;=6>ZbNr8Z{ zG7d@Kn`n{!+7-C5eSr$QWZ;NP2Ihv!MwAYWsP~6(UZsm=B$~tpVJSMc(tZBM@jgJR zurC#@0W%O|9h&<@Vc<6BJc>CMr~Jx~vSx(=tO~+pCMT3!qa`aD9mRv8Iv0(y`ibQ^t@=e zEF#pZmTjE|fdmzd#di=e-!t2e=W1BM#!M;Er$KJP5eJ^b&N_$o-p z7IWF^rq|<`VfJs~2bG$SRzjr{9v++u!uR9y;DG#>O`lo{kZYS<1snGYtd=?xcbb}K z8pjP$PV@fJW>EuPFT9t{?W^2O?4qh&lv;olhLdX)Eu=MjmOy$RA6*oofc z>M3{oY&&GQfOa*9wsTz_4|*}#QuIW$PIx#jv1I1bmb8jnh5F6vzPc}qddqD5%PuY> zrWm#Zg)d<0Te(d!9KxAC$qFO^ffw2eM-p2udN1sSIOE?zu=p~Pe(O18RZ8qaLeAydg^=M7ry&y zMh0Ij-Y#kRqz-kdehl!V86IfSYxs46N-)O1PgL=HGWB!`YiW%+@Ph-Dj%Z$wWsb@k z%<)ZjW{OHSD_y8_Gkcny==TeF4R~p@&{o=zTOhfEJZ^rygcYhi=a*w#?|p}rA|GRg z>Y~l0F`RS~=qEi|Iu?CtN!skBFI zqi+q^pFb_DGCF*n_qf0?(e$xH*_7yy zE}xFF6{uJ$=N|*47WKYX!Qg}==PMFTkTa^}M}FwSir@E#{X=+mqQSy;_JW_cLLUVW z=~TH6KV$}Sn}GUSfnj{#P)djA(^KxSYsi;FSv%{!Q+Z+YQwfWeaD|q$c>ne`R!Tyr zmmKKm`BYhpu{?+UqQP$1i*o(j)`!fv z^R2m$xDJdo&7PGDdrcnolot)Tj9>tV;B;_>8&tlzxtqpRfBOg-NWlNR3`Nh46o9j# zMNyg~S^`=&%AIxhAdr~;v~wfq*d^N5a=`MrQAB0(5Y7rf!1`KcB_8LmHGhcVObBpz zd^1VS9_>68)9e6L3Pn=VeTjwYO*^K=8T#^1DG_GEj#sf|aZxNoYGnMWS0ciAj!|^T zJrJC}Qg4{HER1Rk9xr)!PdWj-^~<~7$5zQxQdg{1cFRzm<8QM;8?`j{>S&}c=@}Q+7PS#02uJ}Y461Xkw>HFr>RsbrnRvu`QF3W(HxIw*8n{w z(*SX4D-coVRXcdTJSEgzQ5U>6o@31c&#&3VF0wFahDIw8NWnynAk|F1Y&*&5?Dy}x zE*VwXT5yOMlANFxJu$DN)nHHslk;!^BePDq?t5`U=5zR%<#tA@CfIClGa7tzA?wTp zDLztUJ0=JwD9B&Yf_8L%M=m^Vx+9R(p|^YQUSW4G$huduZ!+i-`G}@6qnq)Y2^^|5 zo__XH2W=c(i5BSpY6(f~Z@$$F&A#?(fTj)FFS^QwX(7F+look{Kz4%?HmB2kA*0Vg zeXrGX!zVEp0#K7=d*dV5Bx@r7gCtOyRZ5r}ZG9TF_@%qAej3kFTK`*Q@L#;Jvc|iB z%<4DnlUL@b2{Zn=Fr@eIzyFlDX@TGo{rYV+?mNrp&U%5n2JqFouy`9PR1Zpb7poQx zA-TDlP%USCCFw#a*$p0o06Xq4D9X-(Ej0*fEvXjg=CMJc%>8yQ!Rm7rDw7>r{LYb+ zg)r>Y5s*nek(9xTq|2}PtP`2ry@yy}LGb{{^1No_#Cw4el{n(+0C7EjSWE7Qg7wK9 zOqp_FE%<0&(YC495)+$o9Tv@5d)zW4%hEKmN0d6XK<>321vBOj5n*q? z&A`pK3Nn-o5Zr=v=>XcDRQ@jbKt4|A6ALXB?S9>_LiCm&-{%F=D?@P(?`~C&6ML7v z`_li+yq1Q_${e{%SPK!&G0}7hJJGQKLd-m7t%=61pKu_n!h7FZZqrHqL;-jqN?8Yyn+=9ll z;is=E{BDBwrLBl}3e{Cr;5OTiIvW7iubZH=1BWO^7IC1Q>d0tKYDUai}7cEAx93OhH42v|d(<#n<8feagnh zbaBW{!la7k%%VkP`%2|f)h^)W3f|Ob%DND%Dw-KRa$v;WmlGKsN*h3Nay8M1sfl|R zT=iJ5$_bN9z4j-2?hHl?!{j6;)w%XqlJ z98Gvd(V{#oB}?>+o}#RdQY6B$kVKJYk zLS58fdn9iwD-`9CLs?-)iKi&?+UGB_BWIjkDx>Oe+wKqV8*(DK6o8?H*_J78rg>F` zyhsG7;S$WhCnYR^orofqnHKJ)kOo_hqg>J?=P#4=DZZXd5O#iP!~PF-YYq47z-}EN zDy03GKv*bpr$99M(d(M;%u*v?s6)o9-3!M!DW8-Z98eAeUc&>i?~5@@AE|iiJv#Uf z?HlP|*0Se%M{ZrZx3UYjYrJ8^Fj}F-od6ue*>E@0jy6kE%1euLbH1i@>-eu#{EdV_ zg+@zmuI$kAAJz433qF-hJ08M_?`Iv!ULS_{RBJ5D>a-5Af5prw>JBh7xrXiBR5D^@w=V~{pk~VO#&UO;0WbK97wsMD2N$#D`2oY4 z@}?u3U?c$9Nl0x?m$NNoNt!;`r>%4XLI=D6Dfl(`+@w>9?4FVjqdZbyTkJ{4jhw%1 zSPdBLb&~uNGsh8iv(EebR6*e;TT&B#a;d_M+^oH**ojD?jr5d39Di^%L$YJw*zpr| zXN}-Dl_N6eVm_?>4R2Y1oU%B_APhLUF`zcm1IbNzuq;dLoo3PtDiKETz2dL^o}IH3 zs;3>g|6$DV+MoX!3}USSnYlADH@DS$F;Wz(@?wuobF$j2)*Y* z?hz+dzW%37$b64q+T7k3lG!I-z_#9jHB{23OIg>8R~TC}mvXdk8+IGpF}&C!J-pD1 z@$Qtb)19U5Tk2Gds@4oW=Nm%WDthmhZ@>bM@!SivsK(>qb!ha6Gu>uoU=UR52EsHmYW6=*S-QBh%0*miv;K` zrm;|{9q>xx9AFi#6-Oz_Eig7(EYH0I*2Us4b|Iz=T-(NZ@j=FE$+7P#E#bwWrD$QZGz^SFfE&IbR4KlFJ7Eixr))C zm)K3v1f{zhGgX<(<#r(m)UgyVW_Ia@Y}}PoIxS=}t&J|Vd5~ak!&tT(3^u}++kmT! z=|!?APdaS9P$tN+4L|HolC~OF;t(@T+ytC09^RhQE zOgiaaJoynB)@3uGzL<*vjZfEw2IOj$%U7q$bpg&wsrfhCPoskR`;{N?9e8;egqb2d@rw!xq1q zmu(aNZd!})m~rY>fw9ZA@GVIR1~Q}*MbBMR$^AxMyWP|~+Wh9!U^pB-CqO5@0~>`6 zJ`2vs!nv%fpcz%8E-=P28;36f#rD}Ni$EKxNaPZAr$&a2+8PqI2%uK(QeC%pDBpx* zm}*}FOeXT>(oVMI4hGED7Tk&faN0W7(#1sMqH2q7x&?{P(4=0w>^lof-6OlYjWOu% zh<}rfb$ntEp7#dGkg5Agc$BkJvl7zbfKs!c@nq=S;N=(gL|?*X{Q3(Y=3iy4s)m6t z3MlQXZji1G4>*^6p*7#MO$G~Rzk61d>GM_4r)3C+*VokK-g6K4IaA&;#Auv-cr$5n z3-FnV-3BNbG@SRUaq{_#wKuV{k$?mGtr_Y@Hr!#}tX#*{%)obIb0_;M zWoN)XfnyUETT2J4`YB)&fYVAWfwdjvRab%i+dz;XTxmArC+W5!ySRxZ)x zz*Ublv&&xv61F`$#kK_MXz|ZqEgS{l15UZ$g|fXca&JL7A~_Zz9%$}dzNhKO(Lrdm z)rR19KVLD)KK`C|HE<7u+Rw$Bf26wgR3BXnR;WQ5Z)=}BoV+$6Jyal? z&V%Rm1b%{Yc=hb&8SG^)IvDIw*c zEY!^)k7bquH9>0>AO$oS8m}E1A34KnFTwI@1MPjnEt4eGFcAaMxBSMkpZL4_+x(qN zPQpqdcDkdfj#zjZ+`Ez8IJgkdLFiUB)8aNn-Ci2jBR3gucvFTHmqv zPS4hA?zdALW>1-J8q{u=ZLX>Dln!#V1rQe>JPGy7mdIz#mx7SW*TMUjQh~{V^Txjh z!{!-ROmBC~*mjDdv}Efrh1Pt0Sb#hmHQ9Tayp2e{rpcf=dc6k*9cw%#?EU$YVMfIH zwieqg@gGhoRw4%dv6jsCt5)6%^s@OO;p?|gsRfDcEc9zs^kmZP%P2s34DjKJsgc!f zEa<{x=u9AkEIy_A_U{SPv#($t}z2hVONngm?Q z%*F=#;lB({RWIA7m^lbxjR+F8&?M`!ja1v4w-X)Yy#7iI@^)ALPP_3_s9sIngxLF) zyIUsyMh4VEm?oXhEGz;eg#`KG2Y%lFU}FW#P*ZbkegQzaN3qHx7w>!MpH5EJb*Ff_ zs9f@0thYTXjzI&fChvbFLZh_H(3NH@Z(V)#fNm?g@}z9|$KXuU!Z)>Z6+F6+wK)*9 z-DgVZ#(>=9G3ZP}&tF-llr<3huu6G>-1H zDZnSz;6`VM#XSXy*e>)J?!E`jy5$?Tz>G!gszg0;yz#-DHxD1dMYB*g7fPJ#XEmlR zLp1?Ue(af)qyz^>61|e&7M#1Kj^`k=D0R86H!-E=h`!|&Z&Ea2WI;9*p4%j7_G-Y7 zjC}XT**HLWaGKzo+>&ZGn6BLtO%A7@rHnp3m^}9K6u!KBWWrY0mrRG;g4er^u!I5J z1EMFa&{>R+(0@m-oUP6Gl4rHH z+kU@-6_Zjx0>>*L=^sXeslDsKWjG%23s4B3&AyaLHQv3^-&fpAlpxk>Ro$Sn|AC7rj}h?x#`n#$LexGErH`c>bdFdP!6rw>t@1Jw-UC zTL&1`1AhH^+5iXBZpeHd23s18J_l4IH!>IjoxcRJt!LTi?4Rpr^;-s~Tkl_DhlT9o zOE)y_K98Jf=f?LVTUF7(L)encbJS^WJOdArsT;TUI7S9DEw?jIQJj;Zy0A_TdgxNxXG?_IP&d}+ob_}8epyVdDCjO;JOlJFKbf@OdR1D& zd)%j}9T#9nSN+~@2DmEQjnM-@2USQYI8T=knQlqZ&5Rb#r2-`(SB4$Rs9x(LjCVg% ztJ0Dp{1UH?G%Uhg1pCbCC1f-k&aa*5in}73?zU}boNR!to0n}BX1iR6;+*j)uyEoe zc#<@tH62sFGI0*OR%n%po`Jg*e?V5K98K6v4`+I{ZT0uD7w(P=X-Sm#b5O$N`@sq+ zRkK=BE0jjdOCj&G#K2F>67!DxE|t$mS1qonRF^Ks-iN33W?I5Ky&^_N-%1JDH(6GN zSGUk_YjLM6T_$#SfJe>y*)Wr8_T>;iP8vZt!am}Cp4;qIk-fM;@I*SzTsTfyV{)ym z+a5R8mAvnXJzN+cm5JppU8pv1`!O%r_=+dJT1Ci*m=^(~lP01STy7YVom9SX8auhC zZu;vbSl-*D4$i*kmmy#GFFN0jl)5pFZ(3n;IHp48ZA5YjRuFR=4mILj&WP-52%NpZ z=!+OjZq*ZZXpQg3`L%<=;(h5zcrPIrLIx%=C)9it!p@=LLo6UuY^@C$oiDQ_7Si-D z@RQvMf|{OgdyO$go%=FHpfVWV?&|gA!`^-1q5f(JymD~}vbrKn)Fh(BuURXiAHxY_ zEiO#^4K7qHue$I`ua5zcMMjQ0HG`;s>Gb>W(Ov14w%jxdati&Pp-=^AbaaEX3G*)0 zPrPxwye<~ILTf@DP8A@FUlAQ(BU*EMaM6J{O_4$$+71^L@lTjb^iW3CLr-*TpKKN< z=@^+PnLY+gw=5~&Iy!A%OgCnnGwKcWjk0z??0jfzRiA;N!QzE1!ICD+e;yi5~o z_mU3f65ibNH&!$SCx2m5j;g@O_KQNy{|DwPs|&IETYitev?+MSgSynKxC2OgU~;To z-^KBdq>|+AGg)AKfVi|;BDLwOSUO9Mo@U~@99NC7Kr%-+{Ilf2<@HSG1 z6i9Kzx6_`Vc6B%VH{(Zi~*v2AZJ@VW(9qlTIKIL3pxXbwN1t%M#B9 zb)cxp7S_Fho2uyg6Zl-+2H7KUpDNb!r(^@GxUKxsZ47x^||dz zw%gHZy2@hE$?%$93r0ITvz$2Q#an7vpaN}^UW@$R+C!-B7Fk~cz)TMZla=h?HX36y zu`^NO(aFy~vgpbFZf%_T>V1y6VzeM|Wuh1UP9d&QO#CJ#0?gF|yy$cgFx8g1IuhZy zY7g9XiT&wMldr~gWHZC`9z|TVd_-t3^){rtt`)1>(`JXcX=0|g{*$-okj z%fFyw6#*^>Svse`6n2ysLfcsg`Ii&l`EqZ;QOmO!$0yD2ALYYvA#9-07VVEDo5M(| z+18_=tp!mf^y}7#DzSX-?5S77>5G*Rp;z}FlN;udGmop6j-Y~XUb}rIT$8Kc7=n_jb- zaxR?W?)w%XvMv6R!cS&r0PScsl~Cf~9FGLP$)kYdqboa!9}Kzy0~zO3@$-_J>P1=U z>Xfjrch%fxbP|k^^%15xKzZZ z1P$vT0(=K(j#V3ItneYjYPUV?$s@kM1Yg&4=1zc+a3ve%Dolsg6<^V@RVnLM;pu7P zLLO(gtc>z5MV|l6`iDQ^;`m+%04=_!TlG)0xMh@ebgxOIHZl)ILWeZD`V1DD^tOjx zV|&~P+R@>5=z9_4gyF!3x7iKuJ^`wU268`>0#Miv;O_rBS$uul{|mCXJoK66RGsB7 zK5np;$yI-GOM5g?>;j*qK>A*;YI-!Eee_}2pFGr$s$O!X*35}&UY5^idDyJV&CemO zbLSHII?AOL&nj z+pvU*-W06!xPaG5c>U#a1>^Aa{)yc)g3X&Q^1obXklmhYR{vyuLt@#%L177oq`J5; zUbNs0^tR)--YGSJB0p-nW7)GjsbItAQ>vhZbrEkcKdB-xdHm zh@VrOp1?a1sh9%>J;Cp(`S+~0=7VD3YY?Y+?m@=#DN~zhg`lQ%5dvROc{=><$q)K4 z{bAc?W@pa^!Q}G34#iW=RXR1;VTR|?vjFtYEqhOv?KePFzr4~*UlQv8-z0}QzE~i^ z5r2ICX&PlAY%TB-G@j?Yyep2{2zsdc zobFXc%?Nh(K^N*z1QRWpOY@yRU0Jf5` z8X)E@t=7z*J-Zq{we2HS!AWJ2kjbH98D{a@@V~SKdwBI@?}5w_Fqh z0Hr?lc+5^ZQ&ZVdv>;NWuE@CVhYkiuud`qWZpR#ET>xLV7=wy=h88Mz((4>Txd(3j zMaLCY3)vXT4L@qSFXx)xY+b&&-CVg!05d6e>CpUQ#*Cf_3)} z*;?aqm~-;JoL7M1MkAS9&n{mh+Q|xS$%4dfjTd~+Za5PSfMG|1H$|o{sq431NbHr% zsXT)*Pbx(Z>kmw^kTXik-|1l6JKs!0vJeg0KKMLff_J*ibROGNKr$`tj%ytQaD@!a z3GXG9<~ZU^5vNbi@9U~usS6JFUhaUO|7be2?P?zt+>4*1Mn?mMTW}C@I;ZBjoB+VP zNneY~-?tg4?c$nj8t zU!uzvQ&b{;YWkH0tEzl@b?RL~K6xOepel1U2RQPKz>OcSd;Uu+yz<_;o}4CcEiAu!zyz>h+U z4bhB5EXm@VTK?##uN?h0V^4`obvdzM;qZML0`1#H)kyiL7XVc``M@VeAX#Kdv6}r_NM5RKt3R+tP zMW(1xnF%0}2}KDq#i0%eBvMudYmi`yfXp&P1rjU}g3JVx2w@BfAtYhHSi9ERUs>OB zoqeve&vo|shf6A6+9&V(Jip=o-A|j<xvHZwxyzmJhl z`^_xR5|#%zo>=|@C<<9{59o7oR;s1MWg-wx>DAi!G5jko3vyA*XB)yNJ_x1b55Cj? zXzN|&o%-j0#89$wbHVTIzb&3&3%DRl(szRpm-{u#ZM9X4uMKgbKM*&Yx|wHE@_906cw`wBn6&ZVmjU;4<9-7d4Wk zpGLD`DldyXjb=l#`a_f;n*WU2;=_|?7TBM^N-&Jf>?KoEvKyvybo>)p?beUejExmixNaeH z`WIoMqYq;^b6E1&w;t1L0hs~3C32Q`Au%g> zj~({N<+iW*B;U>k`nSN$BD}9k`u3^D({(U!*6TD?N&OtK9FY9V>FE%A>8tSMP0TJc zEy>K}#<%apJ2VI-2Ax-5B`wCDRXJS5E6&WhoKbuS8@(Yj_SG=HDmPCuJIxpr)uzao zCb*t3++t;Y?NP~6K`m}+!F^f21qaInt53_j&0fl7J+-w3-3BdB)BJGrl3=VXeiBc! zE`}8wRhKTZ!OQPCzvJc8V}r(c@d2flxWMWa2E%}|8hAqgEfB#a6GY?rVY8?bgkM?ju z82Rs9D~xZg%F47(48wldki7$oYFs$?8_Ilqg#5P!+(3%Xpw5dwog?ik#D^sWv-bUnx zq}=0ynf<8WyJZ&_7{N;$TIujI7NMmXvHZ(KJDpY1`V-{_lg? zo!?*N^8x*jTTjF5Gbdq`#V6g%`R_g~K(bMT(izT_#X|Vh%ei_*#}^aehVWf*!$k1jhjq53woQ#25(`_3oh^GP1nlhW3|fi zB;FuQwgi_t=r2zXf~B(dTA27r-5~LFk38MG@Pc>q=;`HfrydAH{=rE3p*k z(0QO@hZ1lX{N77HV3wl@V-F9gBx}|^XfMTRXr1NM!)^f>6HAe|Np3P`|{*v%ke&k=?!MDeF+K@%yD+MlDFl&KE05|oGR6{2HctrbD#?)1>3zYkY2k8fv?V|M*jI#~E@(pQ>%}o(--ZO%>H@o!`tH zBr_i7s6jObz`-HS*54;#9xXhlAFDncAqi|W+~E)umAdEhZ(@G9X0)W_%P^x}=Wdry zCxzA^?+`O0f&r@;!A`;5cKU{t8y4)V)={2c#=G_>cgf_?BNj(;(QJ zQaAVLTFGEGhW_!G_z4ExMIY$!t$*!+edwaiQA>zUS2L?tl0e=U23oxe0dty2ks`AK zjDpx~^!d9+qLQ0n7_RBIkdj;KC>%Xu_xL-LOWXL@7em~qYaRfFI#A$VE3*R_bVXs? zFUt?6q+O?h-fu0+eCp-T0-+HF*=Bg|XjJ&6BZJ!|mDb@$+$Vw-vY%L$2>K*|l8uCB zwQ(Qn$wlVAksbvU%J6PY!Qd+Z7Tp(oG#G#GpiM}O!nnV??O_MR$w&w_$sj$l1lmvygi_Fg7jv%@x?sM1AFI?ULhQL(eY*fjOdww@^cS7!P&@ z@uBc@7>zY~nJa#e+R^RAGzZ(cty9AT*0l2`BOB-92PGG2B%{%0MnUav_w%)jCc@r? zP}@-`FmfIRO9h%ZKgzyh&n2DX^MDQ0>&?m4mQTxbhzgWoFH}tekW{frjrXR%FVKIh zs~E~On{l}ikauNtHu9ZW04xa#%6UTzTUIc$?cR%PS9-LY)_lQ|E1iXBWKfp@F9mOb z{hMxZQW{2ySpcqU))(B&_VpFR3rLCjOr9_h){1}z1JG2b`DQ2*-UAjI=mfRmL3;5w zNTO^~Dn6|I?hR}sJ1EsU+omts#Gh+v)bKW_QM$l6 zL&IsFU*iX?oTE99!(=B&(#G$nuX9Ni&N~2eDt675UG@mZ>n(wQ!(E{+3a*2G&d>=Q zMc1@_J(_Lk-5m9X{VmoCZjcMl-(^z`;UfJ+hdVFf%nqGiX0+cXHwF~`Ge;XY{D@~@9N^T0{AzX|D~ZS)>>J&t0(N7vW)HSrJc{Ay zOJC!QE4n@~T*x;-OWEC>WzT>iFZAmxRwI2?=_!k3PiXY>y;_3~D&Wv&iW?(_JQQb^ z6@D$FQb)b@;G6sb`{)A!5UeiwJCFIWzHF0Ux8DcqMWl+DLQgZi-37mBbiPk8DVWEV z&sr}4L{ZI5-i{HYY}BJSXKO&x_W0sfo#~8INax^PjgIf%ow#F^uI6X}5NZl<{}e$w zvTtVh8?LUn`vKP#b~W~M5~J})w{->XQ^Lf(|02k^C(6Cx_u%6Ylf5Dv_L zhiC+jI@fY1xsP=*$?*<@;RHp5?8biQ1y3^#hjM6iO2q?)wYaq+g<4RTykX&>DVZ3v)_102A5gA!r?p*v z5T<*2%b{4a`mjiK$jiX+^aE7wB)T`Cj%+Ygx@niF6&Z?|3xF48KwI0)ST`p!SQq45 zwZOs0{h^L?$m6=OT^yj_T+(NAudth>)9<{;T(yE??cUnfClO#w4kwsU=fJF>kshjLW{eRZ>+-GEb zrXLtsG5CFzM!8y_it>u&c>rs_(5GHjAJ!Z6S!ae?UzoCopCiDy{`|+SuqgS z^KSrcZ=&B?H`K&%y(s~Zcoo&SUErh@U)y^ZXeX_K2+H@F+vNRtGN^YGFWRrJ_EUktdck0 z?#0Kaf1rmyJLIphVsfteyUDrEWaIQ&oRl-56hao}WiEV>Y3CCqEFD3GU390p2RQmq zusxHgo`npzLHQp_Fw45b{w^ryS+&Dl`5`whE6Xe_{Uh0~wnDa7I4~uWquW%fkD8FX zO5By5ywe-Yb?F z|8HMCiP~Uz=E)CZ#Sz$uA8(V8k(W+E;D+Wu#$NwP{mb;XTaLUfvA7gj@`al1AqB`j zbxv~~@AsF{21yrQ;9BO-!hfEJN+;zc9~ z;{&o;Z$JKlDh>^;?j)`7^1Y?u z^wAdxH1q^m#!t$i$|VoG?Sl z4Wo)yaCv;bl}j`A`?M@4Lw(kM)w%j9^z?QPOJIv z|GW)%X0x(>K#$=v;R9j{EB)FT)a|TEsoJv#=DdqYMR;9F<4P*xn8f-G*B~zMS;2%sGjue3KOpoWtC)XLu^dSo$41JR0iy%whq)n!T1un6Q zU*Y1U;+;u|iJw~3^VT{#1(We!mv$?(?L+4{=2UEie4$S6zv4z630qz z-BrBjdCTRmo&0Zx9JkgfsMp?%n?sUnwO$rAeb(!%Q$C=!yY6bvONo-Dw3Zgn8Q7m5 ze~|F#g#NL2B{^4JYnTnm5pF3ZE=x&#q@N%HhBiAk2*vVV z*I#ns`>s!5aLVI(a z#t9@8JEV{Cv7)Bs+gI6R%1$>fzWh z0mCYpk}i+F?^a7?oXlq4Sl2zb!>*lcf<-YN z&VMK%IzwzhnP~`V{Ag~4;z^O3tC^ZhN{vRrP?|nFH3K1<-A*WBRkYR{)jh)$zK~C4 z2#y%p`kjVtyo(88CQfba24YKGcq&y=a%KS;8lAdWm;{Vs@7kqu zfDC(aIvY!7mQ98E=WwN?@9=l+0c&&C2`FawCo%Jne~6g@2pm<+f3loqT^FT}=Mr&O z#@a_O9c?yVHN%G%g6gr(8=hxAe6KeO z3rM_@3td^0Q(`K9j&Mu7 z>*y=WBueOCq)##l&>#kqUg0mQJaDE-!pXZQ%t8f(V+0#oh%NR}Q$+lw37Sb(aQNOO z|8-c49^o)Kv(dKUaEI+5`1X=%khuzu%^B83!d=O4da7slHIQ4kML9qXpjTk3+Ycj#^{sSG2%H0b;B|?m#F_PAH-|PRwk#qbg|KeL%?J zc|W7W6@NdAk52D*_f$8rl6MwED>%@I2j~^ORwvd=> z1SHzD$gbWpTd&5K*&U0JgiE&w)r&W%$&L)pa}}=A^}3dI*RP)gOv+1Vsxyvv25K5^ z1s_;prz=0Q)AXs6E9^A*T7}P>Lz>C1+7nLNL74F%2ooBQ$VDjXB0{Bw;ZqJ%oV4NG*!A=OvbR;_}mzuXGEr!F<3#cz}> zyPLQ_-ubM6?wQ?62y$$R>MqS$oL9Mb(rpn>Yof}WX`W8&9S0~sQ)u+-ZPhN#dkTh* ztU>LP#si{c2E200=c6cj+VG<&SpLLby%xUHjU1oRcH@%)$eQvImL&vHsN+P8dVB`y}wZ_ zv48kx-l@>KZ}cUPYM{D+1Gvn^LZ}m>l@;+q3pM!cfZu$IMI>-)TU8(P&tCX7(;HQX zH=$(Rp*8>>WPY5Idc{iU)+BpVUg>%JUxaQmZ)R0CV=uNFdOu47J>C3S%$YA<83?7> z`4h;K$i%U(cXdfiytrl}cRv0xDGl-}T@fMo=kbky4}d~;5j)%&f~7wIW34{`W4Fp1 z9|2G=H>_*@|gCB;Em_8~=$e8?U@7MZajVd>?8O2 zF_6IGr*$PX(&JgW_*$XChLVA>ntnmV8T?_65tCx&(5`ChH5d2zUN`I6A|=l?z2qd@ z8wOGF4r}@_GgvprTH%Xnhe)eDP!Y!3aYOFdIH}t(Uq4_mYvNJwsn0zlGV0uEX&dO7 z1zZv|a_-yHwF_noWFZkden{2(fzHrK1&YY!2Jw;*!X7h?;0y3BFqmC>N7Z;_CN=(b ziyxTn6Hf;RPM`A}?QLTiC1S~HE~CRo$PE_o%2W(;H?ykIhk?$~Ve@nEO30jd-4b$C zUGq5;5!1N$$NAv^S;kmmv3>2`c7=mC`$xw^V`~gBMf)MFiz`&H(FzqjI*uW&FNU0_w(-3 zLGW3A9~AG6y*6i;KUr-s__A97MyW;I)}ZT&k^g7m-2w?4Qc8T8pk!H`p<=Q{54ldz z1X^S$=ZVxu>oXRNi)HtPKmKVWoqYvy;>AcU+Z-)?iY^=RO<>Yf)92Gv5L9m%E> zX$!XIG-mQ>CQb-shc1c%@Vr_8&%0@b=XLx+@1wF9K{NCYtN+kGShr^f`w_Ym=3Rb& z^@SS(0B5u&dIU+rA=agSb{3KRF^hP6VY*(nIo^wekXL9Y?*XFP%zD{WYA&!3vfby; z6%+M$HSOOVTxfp(zV&Dms6N>w*TRwCs`{wF#gW~fjSML(;ZJsXOE)grm`f_2A-pE; z;O!^wkg~2jbmzcN!hBD@!#DJGG{0QlRM2vxjW79APi(k__9Ol%44qDUMzoi;HXNgc zxda()sOJ#x+V4WXe0bRfRMrJDj-3GR?kRqdL~Yp7$YYPovhLr_X-1uoA!r6R=|L;v zoz#QK7U2nj%VPb23QfE#IKbdeBuZ%vVs2uNSuK-@*|)M@A+n-Zx-c1}dw*H!XQ6*v z*K`}M)R1S9CmN|C#=jqYNwu1N4P19&HCAgl z-Sbd%(S#r6mu5WQG?Wy=(|`QvkTm3BV@_!2Hl!=xm`4GW#8>}N60<%kiK~MwEfUa^ z?l3Pt%NtQrgLzJ0KumLXnB>OK{}>)hXEyo6CN#SqDuJUr&wbnE(kxnIob)G6>sw++ z=_}Ks%&TnPx=KlU;(8q+6Y%61)+WS_AU*x9zV7}!A-faDf$KDD5Xs8VCY7ih*;9oSv6w!C+Nx!2@`320$pR({{gxxee@1fQBu|&JXC2X znpd;wpi@OP*h|JeB}((aMImpwSC{(e2r!bvKroUIPrR<;k!xSEng87?5pK836;-C< zy>sy^)e%v4(dQL6b;_rJ>c}f3hhZ{{og-e{gzn8n-|<8cNdt&X}vn=@ab_ZIpb>y^QE;L!Qp}OTD?(70C&0S2S@^lx?F~ zj1`y^`Vl65A)GY@jSx5aH&zSn-U~jmq?HfPKD7@>B4kw1LYY3-+%Bp`0!iLJBc6V5 zSEiOiqb~O*jTOc&x>&WlU6xr7|nw2xvttsAGi+GD}6-tuRW#n zj4Ji%n$wy8E%5U9aL?lCki3JCiCbpfilL-csXB3v^PSY#!8I= z!ZMe}>j7`{{F*oh6uv~v2m;Y1*QPEr^HlRqbtjA1Mk#;NGdnh@u;JVvw&0&}=$_O5 zPKb&86Rn3dV!f_IW2X=KFLls=rL!g-&HKJ8$k;c7B=n5(D?U^tI=l;HTRN*ab1s^O zG)F11u7{EBo@MAi^MPfaw)U{kDPkz3prQh(o)f4686~9&kqIXZ=!bHCK~$8Cd^gCS z9o}<3q)cgdV_*ZJkIWF0RsMMt{b9Y%EjUBj#bhGUy!ni_!iit_M*O$CGeak zh|9;VKc^K^7vnwzRIXpRbYVNK4nG(G%1()*_VNenLq2GZ?nYu6mycZFXDROM`vmtz zo);?*XJJLnls%wC0&*QPM@AVB#*DBa>H(7_XRf1JPw?#)v*PdlWvnoG+c_|c{N}KR z!=?rLwqv^WdL=H1sBNvg<8V182DHPPl6}+X0ASBMBEe}y^Nx|V!@-`)Q)p3{ilgkp ziWhhq@B(jEKmlH0*e5TrXiqWo8yZlq9(m$v`KmgARP0kgD)la*&h7s)=S^EG4-cw% zatJfeEVIIRbLBH*lGeL`A`!C$^fLjsy$a{AXKVyU+Z#BAPlYCqNyJs-dp>L3gg`uV z{M7|XAqhfK@%A$r0~_lx1|YumZ;?_B%vQe6JkMLl>%8hbBIa0w&$S+x)~B!uzPkrk zVaEOS*rOW|RWhf6wuLN8$)$b-`(6YCVBh>J?2G&|D-jYWHYIb;9V{eR>6KQ@gL{i= z6N2eNVcF%8U0*u-zXgQ9eLE4iQ77Q2TfA`iz=KR?(-eM%>l^qx*O#>^@bxFI54I1O zat()~3tLhPFMoR-^2(8mAb=w0TO7IPi!;3OKcvIE@Lf{TmE}!_0mEG$C^pU=YG60D zis9j#A>$3=cR)ZQ`?}c^DqOt$AAo(otn)QfvII?DevOp0uHWh`U<_>P-;W5I$vP?W zbq2sbljPy_n`sD%!4Jm~CL^u*u!TMMHocn~@SZbkwP&q>eN)E(u zA)^dXwgz%r-$Em@5Fsb6MV!dzE-F`!(d@k@I;`SvaDxaL&M8nMFe-#&>S0P+C?ds5 z-|P>QqL((h(QSsK_3T$kxYW9qwRwc$L{4zFiQ#K+Q_CWC% z3l6ur2atX2^bExE8Cq=Dbn``XrlKBKh0JhHOtR*f+EtX#(CE&J);aGcTw#0!6!D4d zL%}}~BxE&fP6Ixzs?kw34^!ynWDzvrkSP(L2G=UB1!B9{+h#dk>ka|YkJozjG^pLB z{AQHN<4Mi765f@>2ie{+qvonXXOQZe*(glLLWr|P3@1+qUC~~NDAjW4qXxNhjHW&) zSvOM`y^Da`iLAsI%wZ+I%*7?(Ox=Ia0#di@iIO}qXQa0!v4e<-SJZ)ez*stEPi@^NvTsx1*diK#`n4U1 zlFoieyDRl;e*Ti?cE&5JM+tG(WrggMG;oMr4@#iB@0XCLW=mBTC-*zqUZdKc-$-T< zQSX{l+X*EC$Au@wBAW>L&kf|>em2~df9U+J{vDJF$cqUg&xRH=^MOQW-cyOk>+k51^6HwXl z&W#NU4~JL!Rw&-n0~>ZNG%K_e6s|H>v+a-E)x{QztW#*=7AJ)Tf7a=+PZ_8-E!2v6 zQDM$wa=uRO&cK!W=5EwkU*}+kK<>+rrxWY%^h0AqDwQn7d*F#M>Kd^ru_r$}l=s@z zMMkj@y+STm-B=5om~c1J1Kh2Y$YDYNqL|p_*Jig+M+C?|<3Gs0G9l<~l5xpNWFeIp z3v^;#BuZ;(WoCVeZ{|ta4-B=nuzO9v^-}p~?{3D4L1$5`0TeOfGh3#G;)`xzFKYu} zpQ!0=PhVq{Eg^=lSPjVGVpu4c_+~KHP~8zdI~+wYv9@{|$?U)@-a8$E{i9p>jQKQI zYf|O##=n%x7m^gMu+;h2QmBaV1wSvs6Kus8j{>j14@27~loo_>fj{wQ5 z)|eSPYTq^POxD4D4?Krj1#(_oG70k3B}XSz>$$yEppgY*GT2-Td`;R(^Dvnwb4G!l z>$l|a{=oO^<;;2ymte|6n$KGFlSx@#8He=@|J!wyhrXo~@4gaXjmqryYs4n+DZi+kTgq`}wKCT43|i~(;&i1WX5MZfy9_q2 z)bjorrygWHE4ro`c`p2))w-_cIV);id&7oHEkRa(yXEFTejXw8%yZ2Ga4P_&Q1%sw;=Gqf3K>@OF^5Gw3A9aQ7vjJKBLH7L!kbQfs>V6#r778Hy{)IJH z^ml76=Qlyu7f$1o@BU%UO$EGIj{s|~!$)hb)}PkgU$t9${Czi^KK+NK#eA0WBBx98)u>Gp{Sdg90BXLV$+~ zX)6A53gfh%A!IX}AWP)&*T0ZloN3`_i*NZ_}sqDzr8lS(ytm+RHP%19lxY5jN-P zu4xmSuIO+>SHM1-k6>SQOd(_IA7Ed5PAS7?o{B@a0u5M}o=fL9eQ>I3@)6Eb9VmC< zt;y^_p$*VVIY7=ghT6QTPknSp5y%|!(4RW`;5(78k9+=iZ7%{k#Nl$oz}%=OPJSlt zb2(f!--~OU5%i>aciGR^R@#RN!JaVT=u@}==;LSvj>Th1WhA`Eya7kJh(&0`F-iK3 zT)DwDQ`IuOmbKoJg9^z(FOt5|{#cNI<2Lal_~t}k=0kRJg41d1?f?QTl3$TdJ;`r1 zjd+pl;#%5_Y;L}U@rs_$pt$3Q5YXu6W3)bUsu1e`+iiZ-)&7yq=Sx>1`({G`vX4#9 zFyRaXD%@YZLNxx13Ks=5L+ry;S5&yEVSYU;DqI$z!VQ;IfRRChS9*&#fW8DIy8#>! z|I=^q#If0!$$yc=u5@#{{r5W0RxtdR+L(c#_Z0eGR-Wnw2RMxDZ3nhHE6@c(dRm}% zqvCqHb2bC5pvM?Sdf{`qV&lV+JFdoDF3vP!8uZ%SpXC+R|4Mw{`ORjS0HW?X=(U7513!p| zEwX~y=>s6V5eqm|Wt_5n4WX@`gTby6g!BfL=3wGap98Kr)GV=*#VfTG>1zQ+cG~^w zYGe!KGUydsPf3iu*eL!vd5)I@-CbX64xUjghs&m#9$j%}rEc>sJ)V{2}di zj>I-@dITrvMO}r0h`zOa?oX#}^p1~CTfP!l@S3eYNjIuSS zDszD1ah6nk3NCWT=f+K(MilOPusoE`%Epem@)1mSTED(@mv)Yo`CfN;?b;!0UXkqCYg3ECzq7(%*D7j~cFZ@JSo`S%f0;45DxA*KnJ{#9fqNI- zAeHh+iU8PG{ZC*Ykrq4g2iWK5^X77t2BpuIX|cO5D#mZJvHFYEHZ{naY@n8+K|%kg z_2OI;tHb()0sk?@dtk$_=QLo9erlA1>yUyPV>lnFa4w{*!IVdt^_3eH!%9X)=S<+0 z!tCHZdWpq)i-qBS=psU~Z46z%J!!>RJLrr`%%Hk-&bq7^YXRgw$OYxzzvJLg^Mx0;C)|8%%Cr;Gjyq9tH zGWnR4@dmrxIZcwtfdAGj?d^~=u49*3)8Hi;ycWk_AY_A6CTgAi=YJW5iI!-ee#>lm zu6&u1D)YBCYMvgf5od*)%^rkZ{&6P!i5))!clgA^t4p=ZPB9CI&Saj=U8!vB6wj2S zd)F_AWBw!tAG4_K4$z`MT>w#!?}Rl1x54FlGH!Ogml+9-039(e?X(@e;Yd(KfA+rvVB{3&sY*@x!Jo^ zqF0z_z(FEt{$J8S7V_^S?`^X4kj{@(J=S-zO9uyYMX=2yZZnIuDdhdV>(8=YKbAix zjECF5{#uS%7IKS8Fqw3c1k1+lm}d;u=i!$1m&ZG6aYEq3Ub+l?2LmlFb&D-RRzCkh znLKZ>c7CZ~)-Xxf{jE&iHkdyPdM&ill*uDy*$o`K;_PCXJVr2qt9AF5)qGe0zAGK9 z6)kmRm)}qO+btjAEfgoY*5b}A8|Qucli z-Cr$znGJhC*V<1Y)s~vEjsjtMdK8GDp3?eN#H=q&Z~6OI0qb5FfJ0X(N5>1VG#zhV z)$&JsmpG^gKFfPQ9*bnRAeXgXMC`x|djMF{1|&PB z?4D}~P9a1kE*1w&rWw%q9wa7KgJJ}pnClZ*QH&n;;Uw>F1y8^BpNzg>ckHjas?V#g zeyma0|FCAI8HZ7m_vo5~Y^G0d&sOoKYYeW6K>8?RfQBL5t{J#V=Ey67R1GyUbFPU| zp~MisEPE_0HSly1afVt$*39y>FKOdRm@IcNQX8*nomn08+lOKka0p;}w9vB+;-^tx zl$@C)7G0UXa^UBd8wxWeg_;p3QjfOUKHNQU*T|PehLU_Z)xvg!HyDSm(2nX+ z2jb12ou!KRXl`CA-Yy3ve=Qe&CMvpeq794zwe0;KXJkOPt(%*LQnlu6f?o9q+;;EfGwhKS?XHdXNbAKjUc2xIUwirmkK6t5bO>Q0WjUGc(}-O#& z-93Ft-=DLE<4QYn)pjlb0!o-xGQ1x{i$%Stkt3yi&sHyu_h0RzmXv4EpCJ`R;)D}o zv%YKCz1#>D$83|{E?P}%(_v>xPd9PikYi)wKN09^Zw7!xvi%~5;`nlKjZWdT2`qXv zzy=(d@setz zV(4|KnRKutM~9``($lksF1ngqZGl2hVnR-S66WUU2q-JU+^AR>Aj~~fKN|%IbN7aR zZzwq8jAA_7Yqk;1dF)_DWrUdHgD~MYa}L<5;3k3Yx>iQS3ucZXbdjIsy^Ain)c^vb zpoP(D14gR8CsgGqa6QrmyJbFH=5T-TLUX*Q7@Yv%QZGvUZrM>Hl-y;P%%`^huPqLt z&arL}@fs{<0jOI|{m*r)5d)k_JR+>FYgj$mO&hI^G4QC@vu@sG$l$ZTGl7>NvyvPV z&nz7amGv8Pv+OU~yC<4}8_}(56n94IG{1ppB78?r)tWV7O?XaAC{d=Y9_olIK=}#n z3IqvrY`A4Cl0uq5*6g!HUx{+mCbQHKqRl(-2irU5`i^BW+YwQ_|Z}LGFk)8WzAO#7Mfc8dbo)BX7RMJE6mC&Ie zp~$c2#4-fPL^f-ELVmg)raS#+xbv?Tx6gm7)QrBm(uU-qTAt{V96PJR@A4CYx33AY z6`aBQ1g@jfx0P7Dn{RLhD!gbTJm=uwtQQq$^m&l=F?D!rVjpy+vSD zBaxeftmR+6{xVhA=KA#nWT9?A!r6WgdOvcs4+`o6K*v4Z0~bWK8>C*(CmMW=Z-ge_ zeH?nYPLQD?5V`&#p>6m>LQ6$`l+d05B(xRN!!IPyN5Y+jZ!T(}LQ-OUswoo$LcDid ziD5W+JOf_pVu2Y>8}!Yt^5p>(?OlU__}O=n2x)+W!`sy&=D!xAR;ewl5K}W@<`K&u zW^)$fT4jGWFf^U_?85Idav638#m(fv7^Bo}{MktFvvwxnXtnrs67o?4o-6fFJ`JOdOO-l7{-2`sp*ay42f3(J0P(orwrJUXV$NZ~j$te|W^>2SU zHW;Xb0*U)KD&?W#7d!NyCw3!chaBSrQ5QsZaLYhAx0j}j-FhXJP454gM>m_3Oh zU5%2Q{^DdH+;veyQUSlK2H{Y`oGY%L-|Nj>hb*N=XFY%rbh|6_^&;%!?cV5p1n2oU5f z4s@ZF(v&Qn5e%{-gIzgiRO4#F&pjA$E-X>si`Zk=9Iq0hmcXW%cFt7DyS>^tHEYRyXW^~P&+c!Bf~LX<7Oh6gk zXaK|&-|{%N!wW37;?qCun~&RchE*^j6FoJ?y%o{ z=edKl>njb#1`hhl0zPv^a++qc6o%z)C}j9KIkcr|Wlg{ZHGR}mU>sfa<%xN{8#i|C z;qRPbZ+r48>%cy^a7*ux7f$W&OVQk5N6LU7d|h^$K(%|7`p8xJP?eCU`m8KwQxzE>@5WwW`1*RBpMDocBuz8Oi)Y;jP4cM4izs752YPTUJC z)H$z2eWBP)oZrECDBk0l*spGkLbE2)=nl#vNr}1Y!a-TjT!Q~@q1mPL{_*K*aShoz|f?K|}HwGB~ z=CejW5hSYW3%5TzN?2{*Ds>;)q8|`{?pS;TNrN#CtbpFDV=AcmR_pS?GbIp!Vv?rR z@Vj&yezAWYq$wPo+ml=+He~@+MZIp4s#g{_w` zbJ_^Z9E7@?`w+<=$4`7EiFkl|@4Zkv675iubp|}I*3@<-^8nJ7T|Q3vfG5ndx^xRj z@%rPeHurSbZLB`(2HH7~lL9&yh^g`#!hozwxCt2%%etnI@vVjlp5N|>W00pxOv&P( z&F#Vw`_p5_j#}}-U?ATcj^HU-!uN!QKSFaF*{hmmJ_|EnS+Aip9xD{mGi48BfaO}i zjuK0!Iy|BA=R*K+RY{)?+8sT-PsM@(NI9FDsSA7qkNp%=UMpNf4u~}3Yj8}snTNF< zWbODnQy_4{B$yI&$Sj`TFm_wUV)|?GL9ZjSrM+4U|#QqYoyiC)3XzBoxbd zv{Ylm2}@>~Cv#EG@9%5OhY)H2tz*wi@dTne?-X({1W{(;O7gz_pq2%)z^o(eKGHTKPy5#h;X+&qf!ML=#NKo6;) zMpg7B`Z#p#uwY2ca(V%&6@J3s(sk2UgTEXGfI)&O?3%xObAWUUnxff#qWmP;rjjf@IXzMO}CW z+Po#6lY*ldtvckk%HH&^q6w|LKrcx8TQxZhas_L%!`eqgBIbxQu=S@hLS7zO4&9(H%tpg27Ht+Z4+-}a*udiGfnG?p1-e&2|**M4e1y$eH^Jz(*t5EKap3Z(vP;C%I;dTLpka(;8iVoUVsF z7R392v+%~jay`DlW@4VY*&^1umPa&9%F1A$B0V6o#{KqGvoUN8Kbw z)pPDh1tvtWTLaOUrL6K}XBOUGkk?xc97(@b+A({S&l~aA`U~Kfce?ur^<;OH=behl zDIyS_S8|V-$b@hk^Vn%cBHU?6y*6alk!%`i>LZ1fxQnnX><2ocUjnLGf?A{0La1V4Mi1k^j z#4nnsqzV?c3=Q0FrAHK6^Ce5hBAaGlNQke@ocwh#qr-!&w99266vI(8O1B18ylJ`) zi{-3K8BX^j$qN2v)ec;Y3O;}ddPlXpCog2AYQtU7<%RBKr1pFKrBYzBG?!gSs1?pS z9gBFGbHUuq+-7C*{wf2j9%)Z6x*@FQS<=Qv!k0g_?QCkFwpctid#W~#c~K8->u1<9*N6313E?M=w(*mKZRfq~`5%sZc;C?I`-cw(0?Ez{ZTDf{^j! z%lL+A*=uO9>k2)RRRVCD&i1W!Ydud>quji+{2#R~zETC?K*}7trU5Vqs(Lp^3hbxk zhXHq>Pe0%eoREAWjyCBH^?dL1#1q$8foOVc^izws*Mb-|*r;D%Z1~E@5VD?$U{qg# zALP+k@wrQ#CzrO^{}0mMJD% zZB;WyRZCkVwpt0LsI6)SL248cK@t*4u6)jQe%Ez=zw6v?=bZ2LpLM$tdB4W<@w`7C zPsE7hIAN1iB~7_d)8l<|@}KO9A<>b{VDF6FSgGBP!7wz5J@}J65DrSwWP^yKHFE0f zC%f|vgw|{P3RPu72yB~AYmr7$=uX?4Fk0ogy>$5k?mo!l2wbxXVaHI`IMf$)|xo?(O`GoAUabHinXZ zlRoR<|6vrjLfMR>6q~WLqXUkkB4wJP8@i4yI&I%mj;V6*smi?qE@taBO+_c^(#_>j z>Kk#bTQeZYzeNzH7R2kaYnE?YCY3dhhhDHF2%!!`pAuUH7Wy0emHV+Yo~8Dr$x^M~ zHs(6+ezrhHcmy6RIUKy#%yVd!rQy>rulb9+5!r`81j&XJw9QuK(>g z#4h4MY`j=L=F;Q!v3oIrTqe1zXyx0no@ixtT--|6$4<#nc_hC6JX&ZkaFVZlLrmh1 z=-`UUBZ|?jD$wbgeK)sfuCU`9-6;zjG{PgeHLota$;-IUI#6q?W^%0kXB^Ofy&Aq< zU^}K*dzE?raA*IhGHhH*a6t>^CM39gQgg>zSz8jb-2WBeZj6kSA2b!|?)9fnzvM$Bom z0lSL)F-6q`k&y! zR?-G)M$GyiNc-2$ixT$CU8PK!`L<+xnC1@BdN9c`O)T1p;pV#K0(%F=6Rx=19Gw;e zhn((XTJ$dCyI++_u5Zq4VOs)R^(yvZJH0pAQw|w>RE7pqe#_*AJcK#~=91qrPo@0V z|Kb0nIGA_hJcwb1=!;egTw14@gGAmB`}~LkFra zBh2*ZWZ&QLS?h7#$)E20PI-BigBIl>)+0iZDWff=PB7_=5DqH_yH#uHJU+ma1@KzGv0-<5HUR)=zV>{CE8oXhk3T_S+mHIPNm{y^ipv7Qf5tSbu3ENbr$ekU&q zsiq)!@W1CPS`Gf6`HJSi@y;0LvMRZ}luhFU{pRDpvHRgp`s^{c@Qb2TY;T~l)V!9E!^YP+Ie>m=Ph%f{VrnBaJ! zFL}epjokZ}Ic9fS7vrrF{@U|$KNV#r6}%m-#3)^tuN_xjO&BW%X|*UH3gKE692%Da zs1HuBI!a2mN87#l(X|yLSbhUe{-=60^Yg9hcCSyw2UZ%lGRsz%)Ah7^*pXpQ-jwkI zy0VPA5-hcVZRgUc(PHxmCbxAi;U&QnXuJGZT%ei>k;kII&1GyNUY3m`m{>9g zP>SJ;L4a8P_yT^^+#cDt!#xuZLAy6D%bl0*5-Mi4t@=JAd>>YB8nk9o+}V0g(#0|*J9S2`DlnwlS*2&^X%)*!l}9+h89)I)>_t39_F zjSaptl=*yXrGs*3#i8YnAd2c4gwncdNt-0%;1soD_2Cv8B>3V-n9 zl}$slO!g7^Xn;2I125gC(mxU=_-EeGGogmGI^eDV$v7=xDDQ3z;xXvC0UU21e03a{ zLLOP@juSv^S50(@wgLsTDhC27G{;$O>e|Ft(b5f^*^$E)y*#2b( zp6gFbcv8duq46aoa|?%koJS0#Xst34tUZV#nC<<{KuNH^Z`0=XGBZgM{pCARCp40z zGpOiLr~T*&W~bkT98hx28A}J>=bxz2Xh9#0OAOiju&(`Np~)VgN-xI>)*>|Dc2FGp zd`E`I?Lg>k!N9B%u4ZPtO9FYROBC(io%}VR;@QAq#GR2p&w}_e+sJ#!AbAZ8DSv6X zCMcm$EX>$bzkKXDtIrNW-9Zp0Co)GHFjuV)uuEjIn_%bQs1q|CiIBPK84~TyQs)Hm zsW*aA5x-eLygXO@ojP{YdT4^RxHn@jSs+IJ7Mce94L5Rt`?Mi51Cn3IU<;v<{% zVhs%(W}UjVXCF;6C}7#nV)Qn~Sw#o?I%|m3>Xi;V)&Ui#p-&=n+1u}Z0^6XOWaSG1 zv3}U{21OhdPE`c9tXC{?1QKwjmg=hE4tSdC9_?v!pB69#M~Mt@%M=?^s507 zmE9&_t9+~sCPD&aj2Vc`S=n*i0mQ)PJMxc9pOI+%91c?7jV0;6??*ap)g|d6(`-0* z2+J#X!(ipg^rDV?E#z{x{?m`}xw&Bm+LorMu9JRv^MwiX4rZRrDXN++eq&TJz;sfc~6@`)({bae)N^aoyJ--VvTN32OITXQa#TtHWi#_%VfWK z=3Q<5d-Y;RsKqq8w?}<|mE&dmCX#6%22RA-**ERSyENs0pAA?xK5XT@-(ReCraUKeLxhiv)!8kB#=)(@Y#q%ITkQRqw?S}Vg)0PJ3F&eebB(___=f(yjLE;Vp035oVzoCw00tx`3rnd zxHN8?1m0zIQ#+85+^6>#Geb(O-M@(XmR*&O0f@QC!~IDxt#C={ppB}eG1m#2R>wJq zvG!%=>n7}NnGGfR_RJyo{8@p_r(eGZ!B=83G0Y-FK;!x#WM-(i1P6ebY$WD`!OW>4 z=FXBkYae4h7u2nR@&5n?L28z+XmwaRg*b_$m znTQAN_V2_(T7Kdej~?FC(X)Sd^}XG{(eLG3g!m1pY1{LPj*x5(#!YW?vjGHI+hiAUzmC!QbBb|A=VdzFp2ue~pU5MxBh zUF>KH6D0YwxwzITYS$AmXpmOfpiY|8pmRn2JN*9mKfv$Ol8!gr<)KoZ`F46>_s{j$ z$z-E*(YgX5K2|2lynzQJac!rKAOe4Y96KGEx}2K|fo6v!aNP z9ukWagLFC^ng{xcjNsc@j0SciZcVZs-|}_5DFK$^leWu1g>`Q$fay$9R|5Hl-g)LW z8Qio_%>bi!N^V|jCEy0aS_eWP`)P=+m5FwK^xrSlSC-(-ihUE_Ou`Z?gavv!H-kNZ zVP9SgeM&6QnaZr1+Iqh;z^Dn^S|Zw@_W?v8M0>$jQh;y!pd)^h6-_c(8p;cMMxI(? znF9BIE-i^^Kwf99BZh>5);uob%P|YW`g?$z%n8NM=0WST8#63L78V!G+FoGizqV-o zX}u}fblUHri_YBN{$z^?@DGCQFd+yAS6>i(AC=HB>bZ$P`s|vTsAXd*_#9^rg<6r(lwt~$GtI)sZ?V$N*` zfyjTC(jVh!N^(JH7NhSxfH9!_Y@5lb&?vyKqcHl5L-Is85!%(D2Bclq)Q`>t;}h4hS1U?1oMvF7W_=#`srMH+C%8EBJ?LFjcn57} zJrlD%M(Uql4*9)aNR^w#(|}Ci5Ke-O(1fuuE5K!aT}52|cjrVTPliVFq{_$k?2^M% zHGazr2LHGZvNiuV_klTlg{N{M#v$mRRz^qvE5JzSnz4UypD6+7nYoQI3mF=7%`oa?eXY41Kf0zDY?MR@P$VGG212Z-vJXH zzF~-uKnLn6kHBg4vtMM6yGww^x`raV~2Rf-2&` zf!D;$4k0Ylh&Y`tYC9LQf$4eME|^tHR8_ECyJfMZ+DeZAal~1hP^a?&adA}Hve+{Ssw%>(eN(E?C(w$L-Jd>6iE`%(V04LAp>U-5UQsh3;;D6U?Y! zU)@&W?+)7&d&4}NPv+=oovxi^==#hpP}0TI#yqW*CmB2WEWh~>X`;}^wlFg10D;m<4-(_(?0NK(>3Lm^N~ z8fmhsVI|3&dp3wjqYt=+I+2a2%OW!lZ4tyL(TCL4(aMwzTQJ6-FEH0;P@GP?wBUBf zfx#_v2)qUa8p%^(B#?OXKm)zFt9a3lmAOd+XFT?%t;Ig+D+f<-yb@|;;;ts7rY_O# z50L9fgPy_4&SIr%?@iVOjyjZ~grj+2X-F7yP_*|Oz7CMs{tl2hS%c@l0=DsBGD%8& zEYeQk$99$uhQ`k5NCN%z)x-F1^l!%l58kM)SP<45n_Ee;)h5wQ7(9@dtzo;eo&FW( ze+teTNfSlkQj=jMBX&{H@7CjlVQ)v!Wn`xFN)kU-tk0v{{%kI5{sRq(#M!dXc;?2o znbNGzht+52*&<5a68ok6RKDJhynpbgvcPtZ)!UF<_!c5&q@r4e zHPy2}-^ydDPl!-#<4P`lhMqxM(Is9v5pSIxz`4AzHT(CIxXuMisM*JgL8_mct8n$@jL8u|jP9W0K82SaOo9;fd-R_}VM6UlGN1IH zr^I07Y2nk+&7=VcygQ7t10H-E_muf63^*Kcw&9M;M`$^_^&VNl>;Gp>5GoqIjSA7hu?_f242*@P5OJDW7r*phs{ zBNrRg`dc^4Igx$?xAL2BXD&#rXVAu?*24Etif_^8A>{VrJ(m@q?-S5O0m=SGf@gvH zU{lM)*<)fmT7N2u9@736l|x)wk_qmNt&oNx+7y8Q2pyfIe*_HU)2oQo+IY_+THq|{ zckBnlK|u7F7dWjv+gXB14|NH#7+ykOcQ{(G+RdJ!oY#NqGFPA3xaQe1bbjF!do}RQy z7UstmF5dG%g-+7?D9`R%UC8k5%mB7bW&rFu6JEL=@SVMTA%X*Yfs-qKFCzX+FDW$O zxM$@@Xf$IK(DM824Ml@X@8%!;?x#UB!Y-w#|9lS)ee9%PX;(zm`_qgg^TWOaxqG0=y+`|sP9{FaR-gFn1~)^@ zq(;8c#jsM9t2NSmcZsa;6%E!u_fAa3Wl6|xR>_=23s*WlzMrokYukIP)N3^)Agtk< z`UHF^v@b~94HL4(XFEY%-(UKC&a|&$tvR9$574Q5S!Ol$bWSk#nv}dVQ)wRbA>j(O zVQps8HtTfN8-L4i@l&t;Ro9`Y%BIw@Uu}rd&GUV2ms|%#h5lahDA>?kd5Ia%NKm_N zT6^`$wa@)3nBlql=uZoGRVeKZFUl_NUAyEo+}fKP$Xa94JFd%N z1G3>D9(JPlhXscXaO8G1&l>+dKU-*HEhj5W&YzwxE)TP-+dcHILH@qH!prnDqg(fyxD%^>LYYLQ#y? zM8`K`q?V-j;{h0s&-Ie8*__0LS1Gh{ZG+Ojemnr`wzI2nq*sm^>7zbleMB<)40 z==IBESy+QXl7sxZoEOj^oN{C6Xg_;B|1LPt$Z*)z1gSkn)vlDYyy%0)n3}4iyg}WV z*BXl{+z~~+XJ~e!V+W&V(lGsNf;(8@3r^4UI_#zH{W*Fl<&O1xgdm@1^{}EBCffU( z)avVvsyZgFyaeWNk^1S%skLMF!~19C@;~Q}hMA0U)z>U%{_6hf@bd{E@1kDRxD8qG zCjPVMH9&cT8jt;{4L3rEfT$HWKqbVYnj(a*#1pJk?yHqBKDS;MwG@bbbwAS0M>ldV12sk--KFB|{dWEn0z z(&m7w$2oZ+_SLb!wz!bJQ-JLUPgEWiGFrJ#7bcvMtTrnLKSVx~)uP`x=^E&`f_?qf zez5V2rrsw{1zfGsMZI9rV(~OpC@XR-sjNS-3L=3S|4{wZy{445vLL}xee{kkAWwoX zFmCvr#)mJ(?c{n&TYTMB_uveMnL^NHC9iS~p#V$PPR*98G)7JqWaU^yBT;KD7XhC` zP5kH{w0wv{52N@4} z*guJ(Uz^xBfe5o`^rc_O*}M`j#s~mhKxIUWfn0S8jJY#h`=&P-M5y^UcT4SE^Mf(| z@v7_5r}#26GNua{4S=})K@EOcp7+190D7)4);HFwxM+n_B}U=zDq+u&vB%=hSXxia55Ff&O%!IS zd}zzhG0Z*bBGp^iZtz1)2wD-WmU=}5_4Vsjm2iuj>3`jxJ?o^=gp)Nwzt$3ur7Fk8 z#g~1noQ#V*=IU+-`ljR75eGRdqWSGIU&g~n(UWp8(UGS1_8+d7t|%y^0@9@~K_1vZ zXs(coML++6{mHGK*sCIx&HH1Wa6g`}nGbDzQ>#mP0UYI%*BLF))DLFIdE@h+7Vn<# zf_@Kk9~vH7j34~);hfwr##ym~%BrgSVv?dK8$EpY7QuO8##**pYA)Ij1o88Qg+3)FvEb7_2vp(jbca@}F!9NH9Mcz5B**8ITh z_xB-|szaJe-io3-HNbwOgX`nu5tBi>B3^jRONB`L-H*MQ&vQhy!5kQJtgi1HYO{#g zPVZ6f5STABK*t7naPs@xB^Gav+91uHJJNVT`be#HcIdJ zuG&2f-+~723^!eoD{yz(Tze>$w?q2I{Tcn#L3-g{4beai!_|(BY z05ko<*x{(pi?evFuu^3G zW}J*CvPWc!ao)D1U#*0QIhQZ?i*I=_Ac(A2-wAdzvz+5ga(gn?b^Nfjs2L%@6J~3tr z_k@0a{R>QYgX3T}Y-gU^c9hCVE-`dNCYCp-WMf~<7^JGK*vWHRd0*`>ax$EHy$Sin zQ252*kLlGiz55Ya$7BC&V1ap$h@dcz$8DRNP-!|-cjsG>-BrH2N9C3F$-LR5J7a9-<~Tx7o(`1ee^LqV(t-b6}1b9@FH zSx?WQ)A!j4?F%U`2ELgsHy<8(@XKi{iqD_cq$a8wLj=u5?9n=|qED`T3&9TFIBDH; zwIlo04Id3%*Z!|ZukaTX-0_>Zn=C;50c1Y@@VeeyLO+DlWVxr!Fab32&cX}z-16Lc zh3!MD%^TmQNiWP%q`H2goH+T=&sX|)d?a#bHbVH9mRbqxEkoL#7EpueMcO>?uv@M+ z)D$KTY$fdcPPh*P)Q;fcnT5*+j``|p^bUQmIBat3U*BD6yhnDBMD463p(9RA-}9VC zo0HNeFMQftM8f;EZ!X(ct2=n!2pNN-nvGC>)r@pJkjhFG0G(5Rg5SsUycTRgxrGfb zeV#>Q^9aI>vasE6d}`~JMh1fcG|jN<*L?L7nse7bQAlOtO?K+*HPJiJPl=47*tQ4v zR*VI$hv_f*Rs$D%v(Hrs_7hF0Z**`Wi@frU53NTsk_yaQx4z_f;p6qu*Mvb252oio zA-|8~t&bTk6;hp&O3t35d6;pkH7{YaP(C zag~nm)%Sy7y?&{P{#oo+6t$cyeiX(2HEG@mqoGn`PMgpy#+L}+<`ROxqq#38bZ|;3 z&-&bn0hBE{7QM9uRzFSzpE{kLSE~%OlRalXsg%=x0ui@yLZ$Nccf}HAgoSZh;af%s z-IxDx2CnvEk?BP-VmImuM99|=?6Z4=lON66G3rXraRB8eT%wy&;;wBgh0v1_c`6@s zN9b`a428Ph*XK`|oXoHWa>%XAvn`P+{~FJ>;@ zMh?$TPSQg7&7LKkXvI|SNIZBdIOtW+sDXmLOmDt}y9pdf>nENf1Kn7;n-fpQve0`s z$szRS7l`L{+4MY_vaEVAsQTugl1vW=6_d6my@q$HX(tx?v35PVMWQ&2$D|$A$klP` zMAyzuwW*ZztUV^);T)S*nnCPZk_mdFHE>TFNC%l!?L^j$~S!02XAIB z%hlJ63M(lGW9&cQn@$cp@TXJqSW3>%nadZ2!OtL}9qSjbUaV)ng6}DT^o{n|nnrw{ zzq(Dt?hkmMdh_4W0;DpcOhTpEjs?TngsAYgP~*hPn?6WW z-^x}JW&xAtCsUVxUe6i7^gov<{(T42ls){ytLrnB_!!`}4kxMc%hL`w0B+I57L=XOrTcSiKyukLfeZ?`kNYu{=R*fD*s&89MmF;1YXB<|_?6WxEVVzI+|nc)j^^ zoS@^6KmOPSZ*%D!;6;cJ6aSr~`rh;B*(#&Al8f}_DS`4iA~lsuc#xQC<*Cbq z2gP_4j3d!s&|32}ue9A+ko2^_-n{T@=f0o6qW^r?G?=Xw^?$nh$%Xuj5`wZJs@SWV zI3^husEc#F*x2&HiFTuTGE1{Fi_8o(JgT*8n7{I$&H%b*(d+FQ*cj?{ETP$+e+f@C>oC7@3*98}-Gs90OX@t>kB{_Fl9`lkVca)^e@f$9uV%0?c^7Xt= z^AJ3GNIurz8&kTd?8@4^EdrRnX#c+U*$uoaC3jFxtztdB3TIh0RUdav5Y1P0og&w@ zw$W07v+9<2QxOunu={~AZq$417a~L?+l$p+jGA`%$uU4uu2{*1|6)4U2L?x}@fQ?& zUXWuysdAEP9_nj-8z2E=@gC#IyPenSCwDH=D+JEMSm@>OWz>|9FVT_0749lNel760 zr!%%(T{_}!AWP6yaTOMC&_v?wHNSQMVyhqNHJPBNu8;N;uM2LsdcN3y+aty0Xfnkp z7^5St^kg}2b0fg2X9j6IIVZgr4oZ9*zcFMJPxHX{I`}RmD+I94c=2kFze}8$+|PtOV?|OW-Pfd~#fUo^-ZAGbh`9)*mYH)d*TsISH=!kA`1;61c@_ z8_u6j`Y!GIO(^_gCPmrPR;4Mi3G>+W+>D^{qs9H8NBS?Y9*D2ZUFP$&{S_^V8JuQX zvqGV;`P+sY;K);FNxVM4e?7EQ-C@#mnlt9ah4m5(jJPv+qZx$6g6gNufxuDky+sCy zwPDWLCw2tPT+`UdPoyf`nfRJ6w*eRe@TNrpp{M2VI&c3&P4D-mDW&g+Q_NMML z5M0;QB}9GhP3_9Rdegcm$ti6bd+W^Wn?eXRpRM-QEJq@CO@De0!sdA8%q^Z*Hw}vuFZQ;nXlkCSuJ30`&mBv3dXjUtysYfnBoLTaNrT^yy-K z=nubzv(EI;P(XjS+T~m$*?Z4CFkL>+s0pis>93nK~V->z%2m;NkTKv{=@z?^^J8 zHCM+u2^I2nt?!h^fd0L}+>q!tmCHO8V;#4J@97t!9{XQzs$1A=bxToKxpyYJRZ_I; z^6CPu@=|G}vJ3B*qDvK^(wGpXvLcu6lp7jKd@sPs`jQFv-6ukkzAs%}YEq=!=vu?5`4}OvNN7eOkS{89sUT z&7i4(O`g}MCh)YpkA{hx8!afK40QmNEjTCf$dz=ZV!B zhv9GEdw!v#djzo^)9=l}oINM1i-{qNBe7p>cP!Vx!aB_s-aJZ}h@0oUzvx5f`RGye zQbhxc<|f~e-o*HPHU5~aHXgd_>ALsKP4?Xe(^*!d>h6u#Ql@;zA_qTP6F5sHM}=?2 zaV~aT6?+7&{P?)@9cliCc(RjN6Tx+;6^&$!l8l(5#VyL(shipH*KjT>sP zqmgZ|@BXPeH5rxi{L+nLgNH|c7kp-glQSU4C1@Ls&wV1x2~Z9_tn`UnF+EZS$+StO ziN?Ireii>I8Lqy{TN*V4yni~ceEYLOrq2k65EAX3cBE@OsN!(vyF}N1U0OhrshB-x*9(=rC!+nHZ*cJc* z4ohiv?e#wBHeUx6HJqzwGHmm-)!632 z6T{zwtCLw?*eVYLe3CNh$?Un7>rz_NhBtF)O-(+m(DYBmrY=Q4GRCd)s#KaCSShi( zE(Y1C>+imxPTClUN7G$Pb}q-N?EICt%0Q0EJ&x|b^r{|e9&=!QkX?7V&lE1DaQZdy zzWxcvXZj!!nNh&&bG-($JNvhuxg>?JJ}67j>BJdmpB=R+cyZCqp{nF$L_26 zLm`od$jbZ2yd+P(uy>l$$0tY=lRbfX$|*W)D_#-gsVB2nm+`BG1KKZkU4c_tF4g`u z*q-mA4!P=qBSTsAVz(^!+z^-N?g6Fj+8a_(RQzpr61l0Gq_8^@$SCs{(_e;9EUB*! z*;s$GXs?W1N^+kV&ez*aa{T@C?B*dhgtQi#g`B;~1Bk9CX$S5!(oeawF z;gg@Z0bLN4@uQHUDqww&L>ng)ymv^tS40^y257rqmqZX{J`WGSvb}g0JQSKEn|p%e z{bd))H&2E)Z+z)^7x0I(Ah}g>sXC>0R-D5%X*SXK&Kq~VmX^#F+!oR#nigvI0(A~)`m)s0e`TRBzEe@Kr zcUTZ5o1E5$f1Wq_NFep+3EL}gO?QTE-jYAOXGBz8cX)#ytVM+PoOeAr3T`UGtR}4> zhJKlsp2phH!}nC?Gzmp6>TC9~i|=F_D_H^Iy48xBqqgWVb&Ugy7n4V(7ge(Z78{k% z3~|z3JVmbv8JI+}Z)RA=6CvxI3xyhvu3!Jk;hdpgi2^Q}Q+t_azhftNxfeQ)n|Bs{ z5OQT_i$%lDI_cQ30Y3Vq3m`IzPH4|S-CpxKP+ALaPQUxtR6MC$W^AMHIKdgpm}MmN zv~5chfIh_=(HP8B;N~2mP5ja9M-aFE77s>7p@n%Vec(pZncLA{E-N*xvvx7PNAjZV zSq07H9m>}E_;t??QTN02Q7X=mW*VzW zov9g7hs*}*_Up;LY$3)WD!*>iw$LTQkj+n-r6ssv%bOYQKfG=s@BWKY`Mis?#gh+v zwdsB3x2EJ`R=2LMrFwiZ=vbSZV!t<%KPjX#M@RY6gSNlAmH?&*V(36k#yE4+1vCqSqTCz*`8y33Y*Zv}NG#zy5nbRJwd z*&|U>{?sdK;a==ar3Wf8L9iPUY!H~|68~o5H~(}Kd?iBESztoY#E|<8!$m= zQ%i%CsWX`6?<^KDs$>Kkj zo)salKY6K2R3GE>a!D;LwrDmB=2{H^KLx;#HMN-GustCLnbha*@S=gp)(4g;HvrX> zK?u=E>~&wA+H7iF?UmIn<=uW;yJz|wLD3=8B5g;-=i5WOV1p9F7IR0ts@JPMhL?~- zw8hY@py6k#`Ff`skVksG3X?cz8K%X;ZN5$$9es_nXy>^tU2rttd-tl7dSJa ze6!H4A28l+v(h9r|BYDDcUvpx*x?MnvoaBF-zoQg@X4os+rA|9SP}4tm*@D$Ty8-D zp+8xCBYQ^z4UftbCZf`E919|kUR=4gb&K2DD*6+?ASu6caq>yp}Q+jGtYv>XqC#xQK zCi=*xLDnEvso--BxmD?OyP+t^Z+zJFQcl)S=V^Uo$vaZEK7$7O$h^oYHm9P0IOF0z zpZt;fD#G~n{vMAsMHS595{p#1DaPZ(F>DSK4CqX{TK)sg@?8jk^a=Zyx=kbQt>_rT z7F@;3t7H!>GgA|L>s9YxeVN5jg@T{go$u?=z9#T)v&uwEBYlH8B-~yEtCn3ot8n&r zBV50qzF)&S&BdqGgW4BGrv$zJ?djSv7KZYI-BGj4l{-H!fB`r05 ze>TxWiCPcWN3aeK3UAm|6VH}sH6m!vQQuMI<2n8bzaJWaK3>^`1P5H5zwsdn0b6pp zC!?$O)o?nlUJxPISn0)=&c7lRxo!bI*=ZCwF^`54nsjF~>cUS0>GR&^f-6gnk z6bPojT?nc(RBmtIPeO%_ZcYV*twU+gJqSS+t+J@)lZXJLTaj779yNQ$*T<7lD+Q|f zvhR9Bd0-54i;l#wx~KZwc8By<;*-*26( zttuFdQmK5H**%oFl~hds0W@iOYxuLZ{{5Wq8nzi&TcGb7Ls)}fkV*OauU?S;L3D}? z-rt%M<_%W5&wX^!txHCx35s=R_1E-tz z3(D8F>d^IW2J{e+?<1E~!S0I)-`3EdC**`|VyZ|#uV58U{OsYp@YdPKckbeWwIX{e zJLI8p3Za?OFW1-EyX0kc|Gp@Uur`H}nsPC?k^Qr{i`(P#b=`ckh*|EWJXHTkqN$=g7ZLS_fZg zQF`!|$xQUw3D5S$+3wGS0T10^=#LMC!;=aHITs zR>>aP36kV~M&V&r(8bGSb&sp}93%AyMf?=|#G_W-Go1xmH!CMr=M8)%Y6$M+qO_1h z?+4COZx3AMaX57gI7tl|C%q5G5-f}2zl%3LO~yJ7)|9@_^o^S+^Jn)EZ}3pygVZ(W zvH)NTiSg|o?Vi1FUcn>oGcSP%&Uju?k(OqHu~C8Df>5orV`E3)w`GhiSBreJmC;yXDP11!>$)$-?;2(eU;6&z zjall$Q~f~RLk&j^xxkmNq{tmRttWo;(8!%}ru9f=?C}QEJRe>Ttk5NzptWq5vB1wM z+x-xybf{3cCa zDF$(Df%-j^{0Rm7{IhJGVlG1J*E!Rfb8nO8`uypDj*Vk^4vNYXUs6RWed)d~W~`ku z?G)2RrgXTjluC~sMd>*r(`T$ty#ew3c-H91HFU*PY!=X?&zoJpo63DEl$z`PiN z%F9thhJ{r0#?8_z9>W2{rHU=A?xHtJ4-mpUHumW)L!CpdPxS!P=91>d8SV?|w{7qJ ztCzCdQf+{qiYHaSdwYA04#2VREiHsoMWxY#v&y@24?8V{z>(KQ1i~M87AO~wAb2`jQ$@yIwd>Ia& zD-NXhj0S-uEV}@56|0qRY`A(zJ`P#M$A1-vBzl9sLZ!W?XB`UG!876(=C_Fub;@jb_=Mz89P-I zOi+c2uZF{RMK>`$W)Cia4Nv(tlLIuC$imwGDE{w1yTsthiwPuQRd?C%F7PjJ8pUn* zflx0MC=!Sj%FACXHB5j~@dK9?CA8Uc?uoS>rcRxeF7avE$xC@k$`cRKrGA`Pegy1mVUkCRk~>!3HZta1j+qdb&7}%fddPR z2;xi<>X%cZ;om_s^?-e*l3bg=ZDRv@c{a?!2mf&9YU+LW>-2Ov8LqY@6*%2^M&eeH zr|OgJ+(aFAc_z1T^WM3+Z=l-CO>0J_IcwcM{nN8HMjh)D52e)&wG>&qTlkcOQ8{cS za3K4Z_rO2vG#vgSU29vP*Aub5QW-$wv$qcj@Sg5a8C&dj`-d!VfZ+{f$WH5!Hyu+j z`rh+d$C*!v-fDyfd~W00(nd2IuQ>$Khj{cD>d(3k;|0&1wjhG5z1Nn7Zd(?NX^VZI z5fv)J57hk?Pt@cx@9;j^ES{wiRX33Q6d*^GigKu|@^%e)FuJC5> zDfE4PKR^9bIO$?naLDb_3h;A__nF(pM_WQHN)VD+?c1(Od-4o=dk3GWx!S(;c|CS^ z(6$luc(13elqzXgn)u%_)5y-x%pA?YJp&Ng#im(4M{>wZl0;TpSR6?! z|0!~5@E^0PVW;aSdm_^_ObK+|}a{Qd~u?UcaA5G@V_G}~(RTBgw zt=J8OhX2{sNyH@t7gf|RIs7g|U6+Cd-0ZYrLVrxG^sDRZmnK>lHZ?6qrPROacjQQK z`UO%5+pdQ2@7DRyh^afSQ6*BVMs+_BUkOS|3J8;}m9XpnuKuOTpVZ*BGH&@ML{LQ7 z04zo6jpKxX_t~1g#Cx*pNCuze2)mw}*-hLePf!$;@d*QiKI$vmY;sC=`B7~|id7}T zLzLfOS%YyYK@JW*M^(xJXIf;bmh4tK?968BZrLq&4V+B)tI=U2!@FwoG1OIv3JD)J zVqD2^of4x;1?*nP`tz){nHvf&%}YAEy8bL&GoneQEEN5a25BQYO4Bos1M`?}@u(wN zUgxxnn^^@B9XnVLSZ>4V`TT_uvI^n(AJmcs%$lrzer%t=fsUUv15J;PR(%|fbz11s zykN6&s2-9=1kR0RHf%id11AF+V!1>>?XH(Gnl_wwZa%^-lxbenqCH4VVnWnX{o2*I zoq;u|3A~`3_kArJu@oKL`~qt@gg2aJ37I6AXDiQ> z{h{#4veF#-r;r+P7PdTK1h`BlesAXIfchs((a0}1l9M`BN{`tLoHAYct!rPChOjdx z8C~f>Ynz<^jN$!@>u*TJbgBKwYJq#)89=~3lgoHkP$MNpt`O3XZLPD!wykvkc24Qu zK$(3OVr7=$hzMaZzSW!&>G7YxP{bD&a_diPFf9^Za2Uo1>9Rza*4g73p=BVzTLS>wlZZ~5(oj#k4Hd~(<;BZ9dWOi9~^P6ak`y=Q^8Jy zhK6f*fsT~ooY??TG?Wo8*kCTV9L~4{?)SOnA2UvBYXr`PR%ZS1DQf=e7$Ph{+ww0w zuAQ)gX1d=$pRXh~9ITU6>(geWj66GU)6Sr4b3S1?jM&BbDmKr-oaI4w6}s~9N5R^y zRp@=*!VQKsVK8?EI%RZ?R4IYSydq4N@pveiXn)M0+$?{6*wJIqTBgF! zE|$M+Yu$cj<6{$mjmeJ6GxYDft87!`(0)8l!x5uf+l`K<6L!u8lkuaVp1Q70n5U0X zhKDeR$G8*hujU_Si zBoAL3t$NVJo+RZA^DG0~CkR2?l=Aq^?xEp3tSJWwNHAeAL($Uqg1>DjKEN$C?fBpX2IZc(CNNW|r-@)}U z8_7NCrVZk?F$#_9;o#zyS2pxJI69OU)-i{x?uAOlarbw8Ah^BbjqBXj*8)+hut>Fu zvDCQpWAUXVSloUi^ejg=d{sZ($!LsJ$Y_I$-eqV+D(*Nbdo`^1oa8RVl8&sDL%#xa z@}R(H`in&VDOVqd6xyQ7VgoC>t*jZE9e`!1K@9s`=$mimQU3Ao3Ef$TI<+~Ud!@b4 zHh8 zD(6v6j*;VqGuqfGGH)CBBoi4qFjGO3s zk_E*NZu(U_2j#YUf{vmaH+~K@#gpFqtr}yJ9xe&O1Tx;Nb9k2ewD@R8zP@f!*T%WR zJ1%){rXh68LG%vcz#W&3UE{o!bGOIJc%jN9zo?NZo80!Je%9snJF$K-&?9h9xYdS+ zvhl1w+~)Y(MfutU2dbKw+<+8nbh_J*r;iw(yj9XYCa(Qi&L4Ij_#&y2MTvllXt+)* z6tk6;szKu3J1>4VUw)IQk_@H--Yve>i5W;p7k~hj)r?O@{q=O|v+jX-8pTS#kzh;ycNE&nMvkF~=PCK~Y@?2JE7C z_c@Tu?Oy2eZ|?Dx1ZbkPoJ{`4(WlkrV0HhB$>+A{9!1Xc4i_ zjX1VMAWg;}tMG@M&o%tkW!ODi*nK(;WqU3wdiCrFeG@P03V$mZGG-_-Q4jt5S!*fm zh$yezfd0PN6Pp0M9&2NqX?or?#YaSoSJrJ0LCqW|zQdd}ZlofXkl$dA8to1zOZMZR zH%>oYxsO8;i zy!m~tu$7s8%kx`Uf+oFL*!QbB+QZUS#_2JFddcN|qs~IRpS?V%zGE0UNroLt>xBy*Sec&ENlR+4_&6ZBO>g{UGUZx29J9TdgqX_wQp?coHR) zl%?1^C2{lK^e7I?LEV?8B_FImGH2zq+&Sch(&lB$?ZuIfEPt)ZPb6CL3kBf0IBH>} z8uXEH{HRbXOnkuN%BJm2ml@Q2BE9&`H2mFNMH(srtV{>y6xpVi&J$oPeB{Nx@Igh5 z9wF2&E*B}&<4)T^7v?dx0u7~ZmPC@TX0@H1cx&oA$JGmpu%kwAw?}pyuWfubUXzN} zMIW-d8Qu-<4B^F02`(xqv+bu0`J`hhAIZ(c?`pK)0p35Q*Nn&tOL*<+DuvT|2v{XjxE-~k|%pXj^L;e@xx3t|g?){Mv zD+EKOmPce0O<|?%T8>U>HVPWqi)M}pY`d2X1UQ9w%P|sNz1C16=XFgnlBkhsB;0Az zpEI~EOi}P-1kjGrHmJ3V3}Dj{=$BO10Kj4%{`j(Nr-%25IxVIMy2=^Hg{%`bE+l8)x-#*vtDPKa^K&!Z;WvT7jd+E` z!EJY?ZDTZHRQmlF1MH>k^Nv~{LXO86s}I)h&g#2s`7jK!hdz@u?kh@Qr7ldvhuNQVNZB))~GxH2=cbTRcxEDK9 z>E?Pko#f9rx2bLbE>C}6abzhIV%=JB;;8Tf64teH>H*<5AK!kmAopt3DI|Aypc#Re z98dK_YJ#W1&EUU+BPY-yDv6G(G4mIUXoZBKKQ(yv(NYheF%>g|svjJML1@8>h-)lO zJ7U|L_T}IG23PkREB*oW1`0IBy!smJZ?=^_xyX=)v&`x>jL?0)ccBVAJcYNSBZJ7EA?>Ww!c@{6Dar`)+J=UPu``Y^$ z{ez-Tk$8!S!J(BkJnn7$s$JZdls*8gbQ8F#HkMMyt>(z z39aZPIkbqY$t*DmaTC7|0Kr>3)&kDnz^3)u+Xqu7=xXka-3qu%34;~yaGv~lv0p8B z{s;~OLRMhN-u;R5TN8>d(iZoBY@z*MO%@JXl)?*8vqeTqD!bFimpo{DXS4A`-?erR zjp&8TEle3LG*QHC8wbT${Y(i#shB7u$rjoDP6I^S6_>q)=u@6P6B=f2ViwMC-muDJ zkPLEqq=bk2J39Qrz4#1PmaYEMiIN!BBo-+x-_s*2G|=i1i@~4{8k?r%)D8 zyHJb?bK%VD5~JrHOU8@&(r2+W|Cys&MFNIl>e$893CDi z2Qd@e^5r)pCqVB5tkA4DJ^Cr2R*98K6 zSUPGu6JFC;*zqOSltqk(c-G=C4+e>(|K&4tr%Yg2$-l&A5O;(V1yXfqERDhurJd zp0sGx?1{D01WG>srhECE(I=RgA4B?T3CulgmS`H+ddu9c0t^ZJn{Gp!p>;}5WL|iX z(4S4xQ@%7DtX6UIgMay#l(z5WspIocGBj&*w`2=amVH7i%yz-Il&g9n-uG4t>VQfZ zq~~9R-b0k=uYLN|sw+K`&fL`SyVEnc)?p=+kVhZatVTsyvi)mP zp_5Q|FaBO|f_a-yo|( zcS##d_vkf|c_kiKf`__kqk*B;$Jp(S<&~Cl$mV9Np(7qz>LVe-TaZ%jpW>*U3n5>D z>o7i>fT}Hzz_1{@vNXx+f^E*Q@1>P$G=KFhJ1TD0I%M;Jzq)A+3Y~V15QDw&1}?@c z#Z=RX`m!CH2d?hG!8fDgn=QKcKh;K7TEtQLtczzo2?D99kL2&oI`}*5d_2`P=<<;r ztd$qio9q-Pgo^uSzQWkLFARq>Z3KCKpII=>6)jCY<1jtAsPoi7TmX2kAd${ceO|V# zw|Cqn<*JS4%s~5i@wIPLtDoKIZ9L322I!tlVMPV|&vFl_JQgBi)lq(JPkeMH1mBDx zZ_G2ENRMYa^4H(lxlc9T@o>SFPUzxUMMs7a#H!yhv?#wqhE*MT8xaVFiQNq?*myO+ zGL67{m3FlZe!pOxgl&i zDtwRnCiy2ZU$Z4} zJ{2~SK2p$gb1w?sD`l@dn_)$oI(CQIx|P)XzMRTfiOEyyXC@~q2G616__BhsUf0I< z2I41CMZXX*ME3N0xz%`Fxj3A3((_nz6AvT?iTs4hUsr!;E8bUIR!(E8UB<;e6(rN!?~azb zbc@SsxkrOMO$lN;hx(_(XXvPjaXYF8MMCec@jHxqFWtOK;0!_&UBVVje{?79U&tr4 ziP!gF4=dS*8DG0!OaPwGBQDcdU3Zd3Ixkm8cxo0pZs%T>5j{`Aq@^!w6rbID08i@y z_jz|Tw%37Ve;toHsT1n(~Uv@vA^As|{_ zl#wHoD-KxwzR8=_(cHy9b1r`#QkzGm%Ldkc`lJ`XUp{`(g5Q*oPY338z#bcxH1e95 ztd0D1H!|xU{#*DVjupjfnVuN83x?(v6M6jd&{BIzD%Zt&X4U7GkvPrc&_ly>1ih+tG}9?IvN^PH^5eHWqzxAOv)?xNxL2Ir=LwW- z$@5x_k9BtXM;+ppW6Zd z(9n=!I*zFtk%-I3l5h{orIW5fOZ5Rv1x2E;x&uinxlSnT&eE)LE@e-nRg<|QDY+D? z%@hNFzU<4_?2UDtmE%9HZP`Yu+jqp@KK$*s{Kdza8Lpud9+NitF#|e4)$RzkZV6Eb zRmf_49p%@STgjQ?hZr%NkgzQS8vAh~#nENy5Brlpu3TZ+i2QB3fM1jrg9<@X;<&78$6rrH z3=`k>&sx4h{Pb8U^B%vjdR+NmSpcfzK_i<>j4L0N^13}v-`9tG92s3|1|g_$Ub7_a zdYccdgng9UN5(A-ZUilGm5K(rOgL6p)Uhwxp4bpM-==+zZQzF?i8Op>VrbbppsM3S zM)D80*{|S0_Vllv?p~8ycO7N!wJM*a=Q&P!S(f+Va|AgyCHtqJ6(n3(0}#f|d63&1 z>5b# zQ?%50ni4#&GuYaZ6LQ1uAHY%Fat2QU-y9(XOP+17HUp}frhbpyIKJY*ZG+48rwk|> z9X`#~QdZX8{kJviH3}sOq5;A~d`3FPAj3bD9-p zWXjr8e|g?XE%jV}8@<7L1>cZM%NkhHMQ(xZ8*3XWaWxe3IRr~?F+yghQlfG3YmPWk zY9!+L@C4VkeX(9&%;I7@Cmp(#IK@i3kTwVV*uXnOa83+)AbAZM>~v3|Q^#W%&oy(v zv25k?6`ksZ%>v_FlSBhY_vJm0C68(p4@#?)QyW&!g?H}Xjdo1%g>##R@a&Z)<~Ic` zpXN(MJm5eh$3t>vw;l$oJ{M(yPW6^ur#y z-uJwe9bb9h;=W7=Q_I>G=NqO0V-kE-PUY^+mKeZ5qNCu7&#U{O9wv!6{C>7}eDMAI zjT8A77s8jL&3P^xuyVzIuUfKBq7E|=bX&OxRgDjo#Yz%{P-tsiN#2ujCJj-Sd;WaWPLI3P1~h3p-`rHSJh`ptBA7n(J-EKf% zS}ylO_wGP$8`)6R772LvhnsV%W||p@uc%^42o|3iF+aQmunb1*qZoRh%RL0TElS@G zL=Vz?1|-PwFm`zcBh5VKi#i?98@vNPp6}Dg&jlSSO9tbld~7y7iQ(0(HkURQtaf=o z$Z=xX!A>E9}^+gpU)wJdMyUgjq!SR2lv+`H?az?<`^CNt{wyTPU ztx*A#(|F(`QWr>_0Py@u^l3dA^X~H7cNIHHfG4yc&NMEsw>94di|M6b_v3LLpL~H6 zW_~a$odg`{wLg#D)|#%e{2XJtvda()ybTvP`OUfUTb3tf$=US&yHxdHy?~HZZ2%vt zT8`#xbs5qPh3(=wm$Qvb{z}Q(Dw$>D|2F5X1Pf)35rxaySqo1&20=x*W&Sx}fPH(d z+eJ`_gE$;&?)yZm&$c&g2CYurk)X!rN+c0vwCIX6jv_Gn5qkV)4!Nd#3h>{BoNZBp zesgd-`_WUeS1TcMH8D~jRFrzpxeb@eRM^n=@bInyNL+9^(*b$#)iNsh+52FU!La>3 zEO9-7!3G~ewz!_HBOp*sBNe^T|rJ(?{Pi5`wldkP>Xo5SYff zqfs;-+Ov5Bt&*2+Xdl$pV}-ugVP<-TM}M9y<81F*k1>5y^0xE*+kR9rNE7fe zNPkLpWkHizCOYQoH57Rwp97L7C@**=(&=1AiSw8~K!OQk|1Mba!5=%+oc~zYf|N6Up<+v0`#+}a`g!f-e0^b$lf02Q(bWs z$xZR0j%lV*uW{RhI_E98(!D_5?E0T4=0}>2hQAJrvKY2xS26sf1~1xjhqb-U16vIk zjXP@zXpG7F<;S}?M2#?nxHwtlxiy{zHRE~BOI!H`?kONKcEPmZ-9wT|+DI_GhekxACaA@# zTro6!VZ3^RSvyHPeAM!0qXvk@YJOPvT!c!l|9tKcP`4!^tW|hdnhm}MR0(H(oaN5> zrKy{+MM;6C@YT*vKV^`|)~5qlZsS{rbs5g@hwOtgBzcaS{MDZTPLIF&tIyH-LK@Dc zTVRb&Lu}=TAmN5}sv&7gSUzR3hlD5!oU|aeA^+}E@Hv0mE_=X_hoj*8?FQ(+so*Cn z6?scWhOu?&+h|tKE{hCPjO^x{^Zm$jL^g}o0}Cp%Jq=$xO(iNbEN zAhCbX0HH~^3JJ~3<=`K?BaBmcXmwDSbmNhiF5eUlm?ZgN)fn7(V(6YXKh_FKut%~7 zA<(l~2lY~HTxBnpMvUhz`&4jVx+9`_g*5VgJ#ziC7~ja;-i}jr<=YC+RX_8ITRDC# zK)@cKju7FHro(pv^+Tzb!P56qoE+TP_h;*E3-F7*i7->@!R5W(i`0#v5M$4mXC2}> z-`-h&X&&;P7;fKobhwU~0kk3R%3HIUt^C39amy#Btvz($V{Gyat+bSsB~o6$#I}R5 z30&K?g$-NCMUBQ^Yn6xxiG}u&`SNL4_ObMNr~GX!MAwG3Xg0e{ra^W?&GhL=wQSfq zf?>lEu}=(Pdd|3uZYGn)9ax7!A(|Lu)5-tx)}`q)rl<91`NKSy-r36RLpierz>hY=g!1 z^!l#lX0xb2Uz1o2{}AaK>=w10C2{aY7~pMU1u5QyQ_9~Bjw0rcq>_qHw__I8oF zwarOOD{TCaUo`FnYo}ye@S%0~pwFb{+?3Qlg3>X%U80Mf9WCzms)K}|Wo#p|Uj;+$t$k@PW;wthsj zCFlgjHsa<;eQ{Vch)*FII$=X{23?yk4-EEYC zY@E3Km@N^x}#^XezbgN@_d9jc=--4W_t6>!r zY&!Kkgyuz1!27?6HD9|F&j7H#q$2NrxZd92oTNQq-Ulb?FaF(M<$jiPdx$Q-W4yUtIoX(;5^S$S4c|JOWk%{EI@wHN&5xN z(0X%IcBR3&#rc!C^7Q-4Ie<)I&b46bBI2J2VkpROp}R1=Ryf;SulK{HD7ERBYJmS8^gOx5_pC*gv1A4C*@BNho&P>-|=dIUwb_~ zYeXpw0QOEE!@hz2J#Vf-In(hx&W`nSWqSVzw)d*(zy(Z}!#r2^D=k%0RRTiAM80RF zB1$OHljv3BaOc~k0b)06s{C2i|6V_LC$e*Ks76|d3CH+c?KCg=av0`M{`%MWIwt7- zb8xKtL67$LY|Y2PD)!rwq&p=@NzrAo`E7GB9+#CALwGnIe;bToq7#L~YN)hS|Fy+x zu|nX1ZbNF2_4yYoZC!)kG4!Om1@C#Rty!qD>VE#DV0_=YeJTZWvP=K_I+{~$#UN%> z@~f_5utn4q4VjkZzN9ozGH+frQRqJ3+@g8Wlx@0MfjMvZQU!&QiUwcb#J#qQ`Q#b% zaZkrlE%oCP{{zK{=M&(~&zw!)bUMA(mC4CSFK-`AqdlGF`DL1O`IXRf7UFU9`+wP; z{@Ur}7=Z;1IgdoP=lV|iEGTM`xg*^*PUw66SJqp8a0+zxR zsYQ?;G7LrXBK{ch!=wch6O*(<*a4k!DVam5QVztcuU#tIA$Q^|=kt0R&-}bZS47zu3kG(LOVM z;Q8LC<-g^jA=Rh?58Gm(1PWa6X0nksTg39Gf2nQ%p)yLq8~{)3y`;5fq8whq!m-^t zyNynE+Z|ok8ywifgX=6KoP`-^Z1NC~&j{J2&${D|fHq7om-v6Ht4j0#1KEOpb0E@A z4leSg_kqvAke#3xW3`~Yq{l|+JKH|XhPK;*E|*r?V?Yc}H>EIsZlzR`nDRb`u&jJ* zgg%T&P-&aScKF$N-KX?4>9mSWqDK-!V$Q|(sw{5c=!{a<>|yX`O9!{|n+ecwlnGA6 zD~-9XCQ31Ws(0rC@A-T7#P+Fc>epA*5g&S zU;p8)uC+^PIisRw6KNC4(>87pJqNnsMK~WavXefZOUaMtb4;XzM`&Gl-2s&OvpJAdV9uqM_2MG3nk`ojE@;b(2j{$FZo zjA$<}AzhvNUT=1I#A2sTzG!e*Q=xexmiGasFFA*LwoI|1oAMPAh`zAgphlAL_2or` zf=O69cb{BXIvcUR<>IZEXXL7m8=0FOa&qqz<$jNuPt>xz)%MZnuDrs7m=l zpZToqg8wS$rZ(f;SDMsxM=8>~(c0m-g&$0Y0A$|m46jSJFK5Af#>t+21*&rTNK`n= z^mrQO`o=#5NUV9n3K;7X)~xeeKJ?QBeerwusqZU{m7eTrXmYw@;ck)72CP2{kNdPo zLSHRI->gc2KTR+rMnHpmH4gY;GY&%&@tA2t=1DCtxNp*-jnU{0I0}WV9(w^N3|O0d zealuN2)>x`28B)bq5AD@5mzJG%f%A!hhtHX7y*qgpd;m7^au^yJTJ4GY9WG);2KH> z8+>TZG|$c4_OCr!m2L#E?E5Mm%JuDQspp?rQgpq`E3k>9>KP5ldev0Wz7EUG%F#8sK zH*U0Ap6P$FS_RTQm+x+QyATDVGmd;?s2MmUtl%LeKQP#YqsD=E_{wU;ww%f2u>H6v`Mjn~l&sEid zGR6B}4d1_Ulx5ph|H+>lZttEO0Z*BGjR%X*BdSE?k%WzoE_-m?o9|6l8$#2uw;9NE@@p?@j+42jWUJ%6HCU!h zGWPExw}ME%9mepFmRQ?q_M!1S(uj+%T1Vx9 zlgnjvuZ0=&N4xVrQ!DE9Avw&{dRj^8Y{zpJQ88=OqLbh+`~ir?9AIMxY+^Z&MEI^D zNWDbZjRIcw$eT9ipwXaY^-kfEmG0bB8y8Tq_6E*(1+ix)#~@^_>phY zdPT95W!X4)2;}xDx|qY$C+z^Aw}yXhC+foAyu|?23ya1zBffntK`D`~ha^Wg&LHPf zK5SDu6%$LoZ(29NNK*~YJ(|UGq2^XShCI^$00`!IK0m!Ia%LdGfuf;>h9Q4f?J_(r z994tJ&ae1`I3F0DXWs$)I~2!ym1E;SfDm0F!!%ISKO|efM0p1JdNp2g!iIUQvGtwI zPyPsTRy0K>?4V@L^7_b6rhl~gUcjC^$6C(tL$Eh*t75xJ?rF(tQ6xid5fVv(cVTOz z;j~V6TazI5#6=d2{u*~tK_ax46x7V$k<2;rZtz8j`qDn;pwB-^B?Y{UviCb`Hh@;< zAKd+X--n7Io0E8f41wHJejeji=3<%JA3u^{i3%}pkJck(t+kgn7OIW~LzF+_;#-ZD zlIKT1YoF5;+Pk^*F!eB2vdxT0qS4Ju&h1`;7trH1ZV4hxe~8KtBPn#}#SeOiU5XK| zFJoqdE=sp}UpUKdHAw7l<|Y+OKbwgyeRa-hrkI| z?;5k0=&*qKlCzh$IFK5x*D56$Ul_kJM$W!qm+{Ynn|6RtefCFlzQ5xaz;@%7ti3Y< zLu@w$E>_!YKA1*m#_dI%u9gW z{8~QkR%&Iy$4n7nXc7%&FNoiPgd`8>kr+e92w2)%3Cx{Nk)+&%s4z@$o)r{?9_+lA z9Zr(rp*<@GTB`h66wnWpLy_|zJlto^J+myhzYGS_^C@AlYsAhm>I5Di*lIX4(~9*Z zX*_Xgc#@F zDlE-+gH=*4Z9S={uJZ@pw*0yn9SbwOo~g<44~n_!V(*9ozr1^Wel!bVVF?)x_-=RX zPwJBW(9MYSr1Woqnuj%B=sR$m#LQ@)m;FTcO26Ac{n4@p;fv?RYuauq*iE!faC?){ zA;iL7$HcrSS!_yK8^|g)er4KTpq{(OiB)bDnRWI{r7hk~i|4Z6IV_Wv%f z32rSvefnfjkcV+Kp+eGhT(bfyt0;XZVX;uIf5bX_4aZE8*g5J01pQOhC@FK|ZhrtB zFFL!p+?Ev$_-6fyn46pH$L1xuNf780zYpM>{L4aK^gMBge<_RIj6(K1jORMqu!}CB z(uv7S*H?R8c^u#QB^NmA<032`SdVhf5PR4&GP1da37MAX`Tp7A#r@j?%y?b@MYkZ!4y<5&(L`pV|FX=*g{{?{n~>pzIhq0lnUIcgs+_xVA9CUx`yNN z{tdmY1t+296WhxdjG_vh^!Dtngp&t5#I!v39HR*YEb4&|TH`TW0{uV$Kzfl;FZUpg z{3~1B<FfpIC5NTBZ%QzBS$x}>0S!c_9?wZa9{|IH=-&#kfOfOcQd zPgpW~og%txb-c*u@=*nyF&KlfZAvj(}_MUNcH+Y;I>*P^nBP_&C71fm;A*k_?9aCq|jd`a^7{vD`_+mp7c+|0I{IWnPFBK{FBVj`>3Ozuk))! z2QNw}>MrGR^VOWj2-+?DMQ-f3)Y57^&k4*4y7XxJN)&m3701jvxx0Z+H>xH$b!Ge;naMT8r_tQg4?=5r{`yJBSj%%l7CCr_5~tFno`WTVtuGW$b5T-{ zw5g^2mA?>!E_=s@@9RMAo$NOEC`ZsLI2&O_y0Yz)z(-sRD7%b$CAU1 z{bWuTQ0sns4sd?H#H$*&9q$h-_99NJb{bO8PNt)Bwh2U=1c+K`kLo+)RMP6!9-SY$ zFSPS9EFFkuzZZMj%_#$JBE(WJ3uk*+(h z4nAk^__ifoU1ah_*MI#3*y69>!&7ARXD3pDe=D%Vk|=PlrA{P$9)GidJhsscA^-d7ifZS-ERg^EDw!$E{AjNnzg@Hx zDLa=wZg-fYGK3yK06#d2@S0GHTd7Qg&HGdX;9Mn;s1jj6|HfvYLw)yd&xrmAd}a=O_(Q#Z=e#i z;&A>|$I5csxV8lAxZ59N&m4X54KyW=9jFu(im{6TmzrA)8HBDq1h z!N{j5{L!D9&%NnnwzJ{D+wn>o4!@p>cD7{l!jWB}MmZL+ZMif9Bx`!3jD+QW#gVtu zH(D;u;T2Dei=Kf8%~4b@nBr=~;OwDO{m#A#fm0JJFJ#xry??W7%6_}-CX>UYtABB? zUEZ2gt5#3?K(WjaM+@dzV%K}BaZ9bSP#Mr?r?a%Gi_*Z2Z)JEqr@tm4$aR9g`a|3N z6PG#Ji!ONFM=<96Z)g#0ah_AOc8+>Sp2_A z$SC^&C|Wg-T5UqIB*k}60FjG$Qc9#JSY_78XvHl zbZX0&AaFrE-4%NM#%asgZJg&4(Y&_L0q=KU?DE==Rj{o^Q8Gh~Lu~b?a-0GQe(LV`w zc5-NFnAdf@Lm`bae@R=kAkNZCN+sE}+F za+iedo*9}=^APFB?|k7^Ss?^geq!LmT@7V7?;&y^JCD}*fn~&JE5Cr)Fy&^5C&Mla zSlz5tc@lxnl?Lj<<=*QHciCKH-o*uVR;=NEWYZ`;H>^ZoaDzSH7N=}B)_xrQ9=3_W zw9Oi{ta+i;Ut(9p`0#;4(PjSZp7MY65r(%9)W;ANuRw9or}RXf__7ahc@`P?IT7nah0!H zdw3f_I%P6tROqCMotD%hmXUmV?e`%-@#!M#jUe~|;O~L#^vtcxgM2t$q2y%#1bRL$ zfoZP{fHF|!cJ{67YrH>E1=+hv1}G1lcM}wd0}dq<0G<0Wsi|A`Tq!(+uW+?6LR#hF z@52FO+AIGYtljmHRfH^b@<;l;lD5(TSJnT=o}km<$+2yXnk1{rcb3w1-dqYob3j z$cU$vcTTk4Yan)w*~o@F$yxk*CpJ}lZ6dLo1F7$IEK+2mZuavsM1vJI675j`_aD!H z*NcIa5l16cts>85kN=^l4bxySOyeJ1!IjArxNmqJH~- zSbGnrrrYmZR8d4hL8OV4fQWPu6p)svD2ND%C_!3KKspH0Nf8iHigZv~C;}?I_XLDc z#ZaV|(0fa0Nk}<)&%JlfoICUWzQ23s{sEcEJfHpSXYIB2Uc2QR2L2>u2Q=NmEW1Jy z9B;#xIGM}4T`@g*_IP*h#|cbh-uy-XuCWwkZ3?i4IPy|>Ms97%_9@@H5_t+I1U~Q_ z>MhP?qG%9Kc?J!wQVJY zfVycoZj^qg6R@&6Z>AZotVWU4Ge3wM3QxQ&r#U{za{t6T?r>m&t*q7bHP_j~uF!J- z#j~Qi0MtYEDnghChVSF%lo(^F7wZ;B@9G_QaOHNE!VzIPc^bSOL6C{|a z5gaBKD8H*;P+V4=YJTD)kXbNl+};40tf=wu`NdzCtf(LydKG?K-3&78uuA)%&(C=17cS#EEBFvaz9tB#MuRj~lfDc+t(Z*X`N94D z9-cl>Q_GhkEAqcJl9Wsn{2a zFbg-V_FrvNy$0FG$Q)fj!sybjFN+Lt1c|Sa@c=>+$Q%EI>9XC}-Q5TCdJtRl`30jI z2DDw(Pu|hLj#wgnG-8WmgW>n;jTc0M7^qEcO}hK`HTJk?C`OuL*3tcTF5%s!dmKXk z0Rn4|SI2sE6u-QWxPAJH66GO?BmKI(09Xd|zJS=?y>bc=0OX@^B_tTd4t46l2_zW_ zyG5}yXr_7`1|wx?t&4XOr8vUZ7gB(u98K@?Ml6DCTJNR8#WEx>2{as^k>Z%&TugN3 zUqACI!!3KXUV41+Ude+JO#Z{KMWGghaz09ZuB%ImG&YgKuwX9y&GxX@vw)45OBE;> z1H+Bt>pxll|M3x~MPs+pR2uzaIUX@Sz^y>*m17JFu41H30&4O^^m`B@qem{;a;s1LZ;}1Ka?SrI7QtHf?2{Iz3x@#qo&0xU z2BVwxU{M`Z7)L9Yan@DX;lj!WXaB-0EPRGTQDk$`#M7z%nQRDxBAvgVo^)1=bT(o^n%-~=Q#XHmTQp(mi-Kqhs+kQ z@vQbeC`;W)`yC#%Dr@#S!_9C?o|1!TR zM%dR4#28PVkH*w+IT=kSsF(vZ;tBicRFKWIovh-8^RNr0O z{aNFfI{=H0pK>-uma#)%eSp={_VoR(dXddI8DZOp@YP%yK!tq~+?tOnd=4{nR_(K% zxna_mj4&9v$Q`0t`M8~;e?jf1{#qI!rat#4O zgp*TBFG1kk4ht>O1szZSr=)S-^jU_jHlit(yvC6wlH9m^NVG8skbg z6S?1)`5}SdQbP!)%z{;`6$s>2zK+fD0uCe8F541yFvYT%lC+_ub0%9KdF7<}{2M7h zVmsI%#7{qv@%Rfz;lE;2;A+`oPoaGoW)Viyr(l>Ai0j(hZbQ$#g(hK`BtT<<8{wPc zD8UR!+>kuC|E6fR>RR!)({JEc<>iCJ1qJr)Qxt%49(J(=n#$f^{rQPQevVZ^8V>9N;jBg_2mg) z@iz4%ZKs+4yLbAmt2~p5AxQk|)GeRo<ngI@leTAr4)_aW zGS5P;3}IJvkdgI+_g3dwtmb7P{y(D`#B$Pd7Elhj$N|!dPYiteM5${n;k;h#3BJSK zYq<(fFQvZQB&h7(B0=Q|p_W+#;YhSpL>ddLkT*VD@KTJaO4XQCwiIeHiYEcs5c_H% z1%U}I5R6+QRfMt({2Gep0cb4UJNelwMS*9jPLikW??Ax+#IU)Wjs>@a^Kd6F=>B)0 zPK$3yOMr*QD7)I~yTrbTB$+LJ2(_WQ8t-%e2}10~Qk2P%s+Pw3IoYTu1j|>Dm8(f;Xdg8zPfzlmdn=_& zB%I=)Uxd$X{Q5v7NYwjx&FRJPT9{MrRTyiIJ4PwYiCb;PYNvw#As}^{IT;Gf5AxVW z!B-*kZQ4c+T_UW?-@?zMADPJk>qJPBG03ABqs0?<00K*k)7MVj_?W{num4$y?;C1< zXrArf2M?05pq;uEGkRCFdaRoR=8eA#?Y;%Zmpx}+bp#T+%`h?q(kW0dGmZ*rsrY8b zuX<=c#qysLwS8Fimge6gR0nIXsl`jJf&><7<<)-Rw~>i(4n>z;aMi|@;7x;Z&;;>+0t9;X>BG!1y2x?@cm8f;te_8PqGJETr5hjlxz6@G z`UI$Q>aktEo^!gqH^yFP!9F}4;+BksFgvek?p6|6062PrX`m4GT`D0WtY*{0>b)N2FBw!9X-BRFOLd3 z$w>&>sl2YM26IE01GUTVVQ_pFeICmNzPcTAm>adpwucPAkHh_EmC?mb_yeu(JU;Z5 zn|#|>1&-Jx`wc);1y1UGNs-yN+wvafF%zTapJy12U)#1@Vom-Jk~MF!x^>qO6e5cV zSR=FHDKsg~$(s2nV}gCGFBRhRrCPWlg|G9L9aqZ~HNp91H*2B)u2Ugu30~+=4nt|M z_ua`lAFPj~dej`dFI=iEFYg8(g_W9_B+zUuzj~doWet`pKo5f2wtR=G_$`(kf|P}E zZ{qoQn+Ap!0(yr2T6pjljRV=(o{F}YsU~HXVxrtye{NOIz7A^M3C#eTws^UdW%D2( zF*vj*?#!{_ea7~qe>+{J)1MDRFWvroJmWdaE`2TBNK+P*2HbkhQ}#rxC66z$iIBS* zs^GY)&F#`ZDh~6uQ{acs-j%kF15gH2K5sgWuW$^E=B4j~w~^{6)&}ma&W0=2NL%CG zuP*i7sUbvW%y$E9ANuxWBonI$Vpf;}9`>%fMMj_ms>XR=mV{qlTbAfayLw6F?6Yl4 zsCXJO%9|(DE;d1v%-|XOwNbZ3dEk;LisA=C!jOUNQJA|mXom~Y9#U|5Ms8Y@^+h5e zkno^TEkN}^*&`!1enqUe^B12cX7O|q!!^<5Z8i^w#(1D#7Mq!Czs$myXa7ZsGRYLI zFRzI`ob^DeI3IukKQaMDgK9t@%s2o!-zIW+sD`jKqj&^;dpSuW`*kAHY1{ z_2SLZh%MUnx>ae#p_ZQ^R^YGy@@&Pz&hMKcnsAG>=hHPUKRxOSMnlpbBWw`t0xEy; zE=CyGDFLabBMGL)ZKV!t_>|&E{}T^C+)bQt5am;`FE&-^%0@QZXA?sW45)^=(P=$O zzCtKCj^{n`oGj{u*(rX~IoZOJ9R>_!rTLh{md>JeEVP#-J#@!&H(r~$1mPk}D?-v# z?ddgp?}zqq=)6g5qbSZC`lg)3%40#_lG5@`+|oG?G{O@{8wczB2K`$c*6=XEG$j2V z7U#<>+r$kGhx`>^R5)BTA)ai-qMX+pERPck-JOWvZD1faF+;zLDZUUgjMjPdKm8;$T=fXzAT!U!sk5JN7shRcTT}_=;t- zc!+WoUHjQrXAfHX9%Xgqk)i&ti?EPI``x%UlRIR~cSYBl)BJarwC~t-ipK*w1`9YK zHM{nq0CI!qjDamNLIFl%U`hU7fC}N0V7xGFF={C-ebq&lpF+6Gjd{Y5xFbqOUSuqv z1_6#(7^Sk%BPyIJ65J6?umPFC_MTR-(eucB%G6YWAJujm(x7f8Jxi;N z$_fXN!l?wZfZH_rfL{#0edFvcv~!NK6_FL80hSHi{mKKrzgCvWz54%n0niHAdvhN0 z#3)oYV5!b&eB6>qL`}^aRKZ4Vp=;mR?dVYwE4{R;?>XS5`<3DAO-{qjd&xrvuH(`! zb^FIwHZB=;waV~SSx{!)&;3i9Qc2L{uXX6BP#nLNGVEokL}OLD*LP*BT~?P;JQ&>+ zm*4Z@^!W4UPX}PL=GOI+x>h6G7uLz`EgVLmtt8+1-k9p1o=0gwm(SBc*hmXY^w~){ zrULZDXd50SEDhEAow>E~^3XSJ!$v~o9|X4dI$X|%f1cr@k#nwn4{Ib{=vZ3DVoJ?{ zu$f(th89E@W~^de5WwY3bgewKOu4$acm8OufK{}@u5ty0Q8hk0z_MGD{fMFIrd6Kz zIzqIrZ|!|Ux}AOgp8a33v(1x>W9+PED#ZI(1;bcb{F~#FU1wj?LuSIwC@xu+b*OYjd>`Cd@jNE3j60&YTQCdw zXH6J|q|>nOnSnT#-#0U&+ehn+_Ltm;qeQ1EHq&7MtSIJRGp|HZN{`g9=pNJbbsvfi8};<(G1 z^)9cQ&Fm?aS#aSMb@V$}WjPR%T|0Y$R^k2NFOVhSxKe_ZB+Eh+Bn@F zU_S~;^JRS*fkl*ky7w{IT$H+?YT*DMownwf%uVmAWt5A^(K zB0D!h(D|2A+xt$cs(~v)aN~D#9#Ml2jKf)#97zOTemNy;*1>|?%=gZ;CIH5>IJ$*_ z5ZofEtBk8#RhfCdEtJuRi9ZNYf{8y%Tu?xADLqt^q(@D*VmCNbh!HY~sxfVnB{y1v z>J=2t!=*tcU`ieFFzLDO-mvTY2DCoWY=l$93=}9M^y&?o#3!f$L z_V;!cD8$RjLA{e=_8sHIa{IW{^z+R~Bq=|V4qqnaAsC8zT~xQKZ-h@zf@YnHnUZ{( z{rtCP%srlt)m|ONbo*0`tNHC&%O#1j6JG!NLQ~#~#Il;*4#wd2A7=pDUiYDLCqIF~ zU;%;J7>%4lAKj>nJDR1 zw*~=|^r!W2;&@C;Yip);Urf%}Mh)3agbz!w@WjYhld=Bg&ni);)-Jue!_U|Zoy=Dz zm}G5({i4?Co~Gz>XCZ8FOW@>4+W<;9%ZwvqXPBL_JBaW7V?lU{QEIq*V0-=wE=2j% zla{BIkO5^V@hWN(GPHI&d9xP!DE{7$&Uus@ zLRD6Y_1|(P1Ez1DP7dh<`1NJ|Q3kgRE(YVQ&l_$9N8DT8OJZM`SAFoK;{>ohMS9|h zBgXU4>*m77h6sM(fe~)D-^-XKOTqE-(2Blxb$e&ZLp)=fV7o3DUe1Y}BB;bmC9iXS z)R$xO?Q+Eb5G1_y_U!?nBg8Vy5mMr$a+}0$8usB^M`Oo*NDn)3XR)P9g#Zm@;8lm2`UDk4~e>o-^su0g^ zdoYk2BM)PJQn#kg^S}$5durej2%t~;l>kK5?~0*bF-Wze=3w>UB}WAt(O`yzY;bbn zzt9~u)S1T5$#Owcw^X(c`Bf^znRw^kYztt^#n_QwJ`}^rJq0Co6Xxdr2Hg9vbh4Is z!p(-z%{}0g9-WjVA%yWvAuFp%aY>T(P<4upcH;T)=toSk*dxs4r%KTft8n-B!m3h>9 zRtZ0RLoQPDJ>GvY=~fb&F_t)FWFYF1s%~4R&GD!SZ++403*UQgWPIL=2LkEnMfuJ# z_I-j%Wvi+gy!jPZVUprbV;o^Py8eB1CYsHZ{!195TF_o#0#WdF(3>> z(tvNz+?{dAl(BiSGpDex51GP0jncO@@A#%ym|_{VRw)63*fAM3Fq$O_u`*AfIj6dL ztq+-vt|xdb-F1D4AILL`J^_3tCW0e^WhbBzRC)$fL>mC;VFQuMi4~X+Kzvf6|DQ+j zTOAzlfiQEsSaJl?Q^R{srp7MM)bLT1yZWjm=YetW9{2rjQ81F%>O}VLz0&~U6E@iU zu`(~lW%4)Yw08&Wi-;8|7l6-C=a_YgkWwu1;+^133CLJ>u9G8JQ z6W0L=sLf^zX;V=Il#@eEj#<`cX5thZ@8G@w-bOSoAe3UW_Fsz?DqM`RN*#NBv(Y0^ zLg_#S6m0)Ts5$U9bUyoVM3q{I{xZ*F)QTcy&?^g&@R|ez1A}M-__)3XzUj&@+F@<@ zR@hRnK1Edf!{;rJN>Mr0N&nZBz^;PMPmo!ExTAz*~r0bjqyiN!1QT7zZ-eN%>SgoTF zt$N3}V$1QPzHruS=v>{;Wt?IP32=1ca9X+f%_8-( zg7CPYx!=+SQ_}2EhShQN)GlO&Yl7VS{^fw~f8J`EX)7fcf}Xj9wN_UEgn&a>mhHm@H~P@5GUH7^B-LIK;V; z@n6?A&bekjZUyB?cORscCW$C1f4{fYwRuK zMr}El1awqLYIA%sH0it)mtyo8E=t#5LScGE$$?FQZ%8UN>~vD0WfXhPQqk zgv5q^phddy9#9#&FnZ)rC+JOIX|q{KY1?mhVe-VY_pw@LzdJ^RURU$9T}tM0FGL{Z zCT^5YGDS*^;GAUA8cUp5McIv*Wi=5bGdukAvx+%^9vU_UH(l=^0Dr`4~g1o2CTMSU{$Nb=> zY;+haA5VOl2zBK{e=z-g08#K+`}3r(TZm~Tzef37Z}_NTHIG5e(Q2ti>+ZUiD_yi; z+))AebMKhN-VbHd=O*B0HK~O4`6@R~e5cho7b6^Fqz@iEC;M>k2(nSMfZDQZ@F*%A zmNQ}urmp#V;u`))-~M;R-{jB9;2*Cd5=_RDnPn-MuY1&-v!~`UIjGygorTxrBkos# zt%NkY2MVw#D84LPA#Ho}Q&{xoKwjyW^)?BkLyG6Oj{~Gp9b-9S zxUrms+FTBZN_@A18XH5C>9z=v0-K+OK?i^+rEu!;vp4a&&SPcSz9ij&mm1c17BO7b$F0`+dXdpT_aQF$*+ zY_&dEbd5)__5&NO6X)uSDaGR;ZgLWU&Dv;^_bi0E*H}cZJv!7ihaDQfd29s3==lzw z>m=#;kC^zyzUS8FOV7is)$+2{bx3g!Pt>_$w8Agr0*qSPCQH$DP zHkigB%JKQ>@Q4D-v0yec!-`J~3Ml!M5S;#9-WM+#|ZhI@qsj5>Gzjg&&fVu!4T71 zp00(7vT$fjPVZG)Dn6EnH!>E)dXW6woE9JnPz%ast4g%Nm4I@-z4LvSHeb>x$1zx( z$>+6D7x?5-6_=rQz=1s2!mX8hLb9MQPvvXgk6;HiS}$}PVMz-0p3wK$Te+5!t7C0r z>%!4Xk*JIOvQT#(F<**La2K`?s?@5SGkTyF$nQDGu_0^x=y%YJyk$T$-J-T9GUw0X z$WB`LY_bzg(@0IqV}^Bm5~6fWJ(6ZsPg3XKb`|_{L7_DC!EfoV2cy{!6w%KUT zgL7A{?R?V6@3O?^YC?<9Nvn(!UYFzxps;!LGK`-@JN~z}e-E63g z*7y^%5YW6Wn(}vfGAKekyBiSXU5^4iktlmC zo!O!UGPLph68djl3bV+QCs`Q`jA|?7SJh;d(@odq>xMQb6M8}9mjdclt#Yg?4%-<& zBt>F|`?IyTw0DAH(Bs{-&&p{P<3_h#4D*Ak=oso->mXC5mmaSz9@O}Jt-bGhxygS0 zR$9=?bU;c5`8Wu*(tKcGx+T%POE_y@@0=tDDgWgwR2hkEADm6!tRB1y5?W>fk$)6h z)yl6O?1$!r(fwB*z?B~P5>A#DCCdlRj1;|CV!p9ev$q-tmkvS7ww}A_Dst4Ws-iN^ zhoUG?mc7(AayNkMMiaR1LfzBV@#)7)--2suOeX{WN(!to%kz8=UdD~p4WM?DW~hgk z->{vQ)7^532H?@Gkai@x=TFxBfW0aG6Vh*^oHQJ6u@F`&IfqP~D)DN)TG+VW;qG=O z0&o(+p-XWd0b`@`1+tH z7no%&-Y`Wz2TwErP?Hld0?+nMw|R_cFO4*8dOST@Oel?*#&ndlyYO&Ya~gpU+Y z!^jj>%R{b0|5scErLLw`G~<%O!oCRnlu(#BxBl}GeQ~45bj@RP8J;d4yaa)KL11fL z0q&Eaw_A^(Zv3f95%RhJi?3*s%Kag)H~EFFZ6yOtnHBz=S8hn?q<1dFOftIfj>&zA zEZYtU5TbQIhi%6F*l0|(xY~ga(qne3u?n`_pKr3T&vHCF%qhO zDv!amC(b`$Nql90!P}cy2&A0$_+jGtCJ5z-rBHuEru!|vK)(6+73yNF*Px#8E)Noc zP_8YmPW=_jEfWMZAAHJaborfs1%f}tRY{RYIa6neiEbpkcCD?vg zE=ZGo$Smj-d#vcRC|(n^6=y}Gj!#mAE?QK~1-nzbmHn1h8t z9ugsG0PWkyq{5~zd3#d6Yp4r*zr<)6UmEFsZX1+unWA6mQ&cP#FxN0*uku!4x^{js z_uRknA$M%T?}-Q{&fdJT`OhdNFYW2z12{hQ(>$yBA>L&F~NaRRL5U%l1CHHyRVJU0Ola*t4>uwIXrl*metM9<}w)I`6=*!`q0*RMao zJSa(%vU1&nVZtT8&M$D(Q=A^N87~HB%FZuQFbdCl$t~x_hsP~J^tQ-L6$aBWz{9%f zHwzwan203trRKw_=@~*k;vgh}vl~YVqT8v`mXE{({4)HSsFoV5EvMpXgL%D8U2|Y3 zt^n(l=$^)C0hiL-YyKLGv!R1hij^wHyJF}jym^J)k7FugyLL~9%8r&8Yh?l047sPR zVSs5U4$@RjK5l<`p@>wSF!i9OH6A_F_nP`sgZ8=_w@tGP8Tk}6*%5Qx@rJ2UKIl<^ zfZ15T;{`rA%XU`(In-CGEbi}2ri!muAU6Hk`{Akd<^l&>(p+kl0wsvctGL<(9~!(eD#`pt}D?q(=X#9^y9PYW(6M@8ZiX{<=-}$ z5tc1HHvUu@HB|{y?q3HYZoclD`FYS^@J``s-c82(`6*4Gj!4N3RKcT{t#j69Svb&- zt5}4nyqQn477A|IJ@9e8dGmb+Xz`VT@BER>^Gh^+-(qBg;xS2qp=sLcrTi)MBc=0| zMXk5@3ddp~RZdI3n%jGLiwV`SK7F9s>$D3dDC;-5#HB}+V|_He*FFMqL@1qn8_nUv z!y)4Ec_QGn&X**g-DQafY%X$GlO6~+&GxLAZ-*+XUxa8%@ev6z z=~Ijrqc9GmhAPHbq5{fJ@5lG>^Pu*pnKK68EMxW0aKvYjdl&^QqU(ElsUi-wVWG+@ z@#fEI(GJoqNiSEz!hGLuXL|7z>><=ugvi9nkB`F}Xv*<&bu$IY=kWv9JX?p|ck;H2I1SkwCq1nx!)?`1885CTbRj}(TK+ID;x z6sT4d3$H9U8ZxnOgO6H{X|91#!V>;nYpL-&EnmM2O`AoKG6%z)YTd}ElLz3hy6gcB zw|H*vIPtZK4^=h7Bqd@}H$i(SD&d9YF^}w#(pR2SKEj4W$Va8C<~avz+!7CDrAJ1qRuW2D-oJMI?~ z@5qiW(EkSruzu%N!p2bs9}+q9`pkY|X{1wMP1;VmJ5ddqVflUO%HaI8>CAwR!mV!$G5Q-G+d@bFC-slQ z0%4x%3XZAU%mx+>!sJUEnEbaRYo!cRZkHeyd7H1_xy%Op<`Smd*}&9_XDv^kf3HsP zrG2^ZV*&$OF{FjAAd$niZ>@TV)7;oqFc!aOKcO`R)+sq#bCk*9oI9#91e!j3d zo9$qc!8gEd()EhChiJWmoNQ3D&t!2ovl_4|*rezc7G9aLr^#6p_u9$zH92da-mmok zoObo@qt)p51xw)qdeOG}R~qT;v*>ssJZI z_wbDxJl`kJoxb^Rts{)u$tK~fD+{wMcPx?b%nzMA2j|H-;i@mXo`dd0KDLbj5frjl z#d4G681|O7QBk!qjP_yTl5f1NKGgM@Y8LVDsqZ&B8oN0HiSzdWY6qvsZhTM>BE&)P z{A~{BIRO^LeS3X)dqG%P9LT%wV|ekp$TdIHc!mm;Rx1W1N5ojyzJKa*P3@0p$2{l# ztgG5A{Bps}tg!1p@7tG_M?T`}nf%oWx`rEz2uDEgM9AQnE_@{qCN+0d6o|8{>YT{w zWri@i?^?sjRb5$490%Q};-fnVx`jl&0YsLV8m)ZkX*z(xosdTmcUa9dGZ=!?-kbkQ zwI`lkJZO;X~MF?DAIf0lXm@wja;#u??DP}a-`T|G}pkih43=v*d>#( zyPZb{JTZzUSxuIC+IDYW1`WK6Zuw5Z`G9U2no1Q+`w2Mg1k}=*;h?3QZq;eTk_%4O z?T!4XJv7AQNhTo`95glmLx5g-Y@(_YeZ>htojslk*?PB})`lLiEoXxtKO#17YVR1} zzakK%Ef)%ET^Vi@QEfPb8y@m~=urVi469B%D1(|SEmYltwp<0!6qPKWo*KOx(z~3D z4~S!sOi>SOLWAG6R@@%nbS##hIFB5KsEcR)eU*Db6jM=RMKo9}?INJG=Z zba@NzCI19z&X*D!XTtN@tY7vO2pQhXBi{a=dK^1U!zS}xl*F|oJxS&>EUObK}&90Wn9SlS$KR{90f`j9&tN2+PoXp2NM4xLj6l)mtw zNsAfBa3Sa$^GpP6H~X2$Ckk=lb9v<-%{H)MqnvqF7itfI+o|@yu~XSd`wDj+`XnKk z#=ASEA!SovtWgcbTdy!1bOzq#3QHVvz)sIIFq4gfQl69pk?d>fo~pk0AUOax*k{;r zTUCo|XfGw9g@R93;PqeoxaW!`+eToGGGXI;J10Syg--|5bhum$oU+RC?brDcM#>86 zjpwj1vB1)4(noFosC94S!&kl@Pv0>-DybXEoc2d_+x?0)+3e5uc!(aFWUM7B0CCa> ze1@WbeQnL5erW1p7e1U|%#R>!j~_K2hj~n-CS$Cg@;|@XsuSqhmAerL@f%MknpXw= z{BikJ=@`kYuvl2B(K4Sh;YN z`xGk>KWXYW9DJRweal5l1)&jA9nBsXAFG|oGF9&gY#*)D9PQz9W(Vb?5odGe-zb@X zAk>@v`A8}?5|DUfd*W`!z#JEcK0e>5v3@{dIS~{_AjFk1yzYq|w7W4>{DR zl=eNCD>nq#&vLD!OJwOsxw&0Lj1Y|V0XH(4EfYEq4hXDG)PRn2atO?S47XJO$K&7; zM`M$v@9IFoS)F>DP~fdM|4h>y%CgaH>aRy~gZ_OKeXNy}QRVR?U#tD2au+gGZWk3I42r+Laz_A{|Xcqnm$#-&ZhhrDZ4NW?t<*=Hn6%Ae{0^LStOW;AEu7`IQTU zqo@Nbi>A5_9pF6Di}0ztuNgt9oPJ}wQ=szq@82;8(1Bu%#Y-7e*;)nY(niKB=OF5BVkbs+i-j%=G=iz-Q18z*+}T2qe3QQRCXkIIj|JNr2qB z(+rLP1#M^eZd9!`2dWc3wr%!#K$|6Alr48$Z>01T1`g|f;VH9YHgiwTKSqy2al$ed zXdz}ZW(9ZBXF2OZAF8|37_T&=vC8_b-8lq(kGuvaqF$61bZChnRp9Js`6EZ9pp?tdnbGz{mp-#h(9qsMUQYuvDg}QuZbwg+_{w-4fyuN8EuG{ zdSBRZ057Btq#HI&?ulr4+CELC@4sLSMFm9;!bUY-ppS2dY^enO$xu0{F(}4;I(%&? ziFb@P=sWC|QE7(PN|p;pomnTPaj3Q%X$I1dXWZI8-1_Fw&4D1i4H`l4L3f*XYEmbz zC|J5aLIVQT4Pbhn+(P zT-xZP5dAbS{mJ?f0Q(^0X@xHJnuc?G*ylT)XoNovSUCr5^jPwNS+hy_pX~i^o|&rU1?(Kc zssXOkvKDpZ55N^vbwugqJx|aJyO^gG+2{~^<~x3_#m5E{g(vj(z?8IkI4m3|lQPV{+i)%w3?QD7fVpBz6Ili&lKZ=}tZf zuCM#t9~I$=@2;OgUc1F<&Z=$l@N#z1pLF$|8%D} z(DHWRDO*5y*9dwe4(IGQJp}W7(EY;?h#%l!$aZZ-)y32D^nHiMgGd_lN;8ICeO6q` z$TtT_=(5$h%RzF#Fn83F15t?v5*+Eo>D2TdH&tuAj*FI!Dq0(rG^|=>J~3uqmI|42 z8b;UGT53g4`UyL4pkc;`ho#?JBkx?k0HA$(E*qHLCG_RPe3lG|s;JQ4WzA2U?PSah zY3;u$ZPkepwg&{DkssR(Z40p0RC|lb-nF}{Wek+Hq1t@;AiC2?tGNqBop#~$$@zRR z>CTvU*!IluQCcs!D{Z6J7Wp_H?MwIflF+h+cr>JtDdIfMO9ywiRH>(v8v{Fw4_c;+ z)?colStD2IJopgIMgJ#&r5Fu^Pc0;;xlTAT8y@eje z^xrp|-Yvafpcp?XQ==NU%rk!}qVwOZZOU?ryk3zZV4${;=#67Q6I%_eckf`YVaM(- zrh-jUiq;Ho5iL({l9-jD*#TMzQ%|v{)9yBuY^kMDr-r9_LHmgh)PwT^>D*zEfi>_K z5W-`6lgrGIp}EYL_`g3U7rYZkyo&O=Y!Z|uq|t*^{p#Eh^P5n9fsuC~hF#Q_?i~Bk zXc?Eu45fX-QYn+I7lJB(*5uBzkzUzHH!sj5HH>7+wK621ZQmkJ` zySX%+2KoL)OvuA?9{HgW7Sv-xUNoB%H;c*AbC;V{Q4~Pi-#AX7-OjU;`~sLq0-WeKb?@$Z!KC< zqA6VILj~e*P&;jd*UIi18lOq{Fe_y`!=XefV3u@c{^qCeh5sf78+Re}#1P-*jX5u| zX!(yZ+$dtr$vpyy*v&b84nWsjcS?le<&ArpM{Q;*RfOHnrNGmJd>60N^`_(ADzTZ32vG1HeCNj75JKi2Uegxm;!hJ`xnwBPJ zv=BH|y(Lg5cRvUqT#l%CnzdWtCHOKS#$3DELiA5 zVuqn0%p>qJxU!{Qu=n7g&EiMS! zS_b>3IqSoZE~hLb*F2hW2AFBVfQ2B4ZC|HQKZ$mH%LT51i!|Hb9(g{wo$J~L{<9a9 z9dhpPRM)6++XGznFY}rILD+i-HQ9ab!h#?I3L*$7B_JvwO;mb`N)wSpq)H1#q=WQM zKt(#JRB4eKkrGgP3mxgbHwiU#LMVZdeE0Ld=RMzdt!rHi z!N?hXLuN?vr0K{o)p?+BmwK;v$M{#LMYj9Rek6EX-Rfv}dcM9d!w~O|QqMa$bs2L8 zgd-c3YIKseH16DFhhCr-_Bt|c%o+iNOl^jyF5e|U z@Ss-#j&$R*XZpm5W&1)BFj}ekLPN{0w$j|eU3(dVS@r%HGv58jwvY7kXJ$YFeywEp zX>C9SoA7f){UjmghD@{Q>A>mF+_ifpfrvTfQqGMdw}wC;QZPq|PO2d~HQhk$!g&Hw zgz@yFTVI8`8rQ<6L-c?=ewXj?40Kjz>=D_XAGCbDcs0gtr^ZhRY9`Yili?qaoN^kr z?mIZRXCLW0#T1>Fw)d=~Dj-xLI0W;tCDaOVSP~~FB>{@oQS?uRGkgM*#3^vD=D{q+ zGkeYY4p#fxsUEf36dJvOoge$b{oEN8l|Zek*D*lMqMOcXPA6)1Z!+u8%ARP*6&eKpl_Yi|kvll8e%hXV2Dj z1eQfT$R0z`xifGftJX4hNe+;B1~|Jo@-8O(J#SUpkmdf*pqMLN;LqYHC6w!M6xoo`8Cm*&XW>V9$U3bdpIgcRCtTNxxIrr&suo?k1 zA^6xkI0*Z0`f2OxTIrj(_;d!1$#6g;&pZJiyOY1iq?_BN7r4 zJlkziWs9*2Q*;R=yJy7_KMIJiqfbEwW=C^gXa(|_mk{!9>4Bz9f_@DE+R;X^qt9a`m=lz{><%##EG93ZW`8(0fM;9gX4v#jVL{GIr(wO{QtsM+Ekl%h z^J;9g)}Iv>AqW_aJb6V>Yl^+K;Q^ky(`Psp=G2Qyj}MR^K0zLLq5wsEP5(^Eby}c! z;nsJ^Y(Q+ioB@9D#t9HNPoC7@>IFS2CRqSnD-vuDmI zdTeyeH@M&LOsDt)jQ2%tz=9C0@|x+336T5Bb>t+iX=C%rKcWQB;i5{%(&>L{JKSUc zoxRvc25i}Uw9W{$^Oc-==-3`3S^f}ojWr%j&M<(7Zq2@}+jueXB_(HmrlIMLaBVYm z+aSF?;Ow)QS<^>2W|#Q22H!GPCPOW(M5F?eh{i9cM>Kuh23WweVf9aqGRu>?8G7C! z^krIuoF-wj$$|v~IoFBlU$jCL&Vt8P)`Uv8wBDVURjw1e@bW>4bn;oMyf_T)oZmSM zRtbjNGxC>wbNe$O=-CKCHK`y^VfZ!84mA1V&rGX?*-D(OUnUlm?3KA^Dj-p+Baq;; zKoZ+5-3^O#i@3ekMx@zq@c8=Z-hY6~O;?iB7@i6I(+__9<-i~PUG9&^HMmMtVhUw> z-4o2a0p@(vu$K4x4_s`1hqi4kN%))=#Xv$ko8;QSebpGzTZjn3^t#Kw$4dGQZE=b| z0(WGWl0eKbm)l-?LrpX_pH6@hawh`A%$QLU&sF2Y;eIRbvgNVy?A3^Rt-zbNij`S- zKrCQPH$%oFp6jzzZEgJiw~N)~ga}`v{l7tBE@7xFMsFN_EJts0pdxfquC_Ia@%7E+ zkfP&tK5Yh;uS=`J3i7=PiXRy9VF{JiJ=B6ROS|FWjD{DveOr-1xlRAef-1Yy^g7LD zPb*`zCJ*O-C@6ouXzaQ`sF-h9)Nbn1hKk^{&t)92-FIjcnP_j1u5g<5HL8CTt+2PG zUGb)Osu%B+NOw;3h*>zo*+-F--*0Fyg!&{I+jaIQhSTRjS^UY=EyI=j^}nBdu7u2) z?$?7R!Q26b&kHu*BGW%kWYU0MhjROtXtIOn?%ti%X1!P5D1C~o0n$N9MIkEogQ%op>Z z0fdnbu!9m&QF_L6amVQ=xTh91K9N3_&JjS2GpY#myZkeuS(VP9Px@zzhD*_yF+5gx zUK;fte6GI2B$R{tVUgHuWs9Ghoy8w!Zq9{|VC=J|<2Z^h&ljtbcn*x8Y3# z;#lk>D6P@8j7=CgKZM9DETO&>J05e*-o0tEfV)#;}s0f__1IONqD4AqXvYsTF z-s+M@3amzbLgE@Bi>bzvK)cIhmYf0=-zBbi6O0>EyAH z&pt!U0JodvDy_h0Iwxgp`(ANP!XJ|FEwRYCPjFn-qXpmDF0*OzKOOD@<&YAI6Zv** za^@qUg?X;XhYGW)F{#U@6zWp_euU#3@uDP3R^g5j?&OFN&mU9e!m5Mz3~>L-Q~lZ_ z6fs<3%S{NmXX@<^I0Sf9lj(tWMf(M<-eAv}HH}|A>JMif(9Rn&!OJJE_t_^kDGFo)-8J+I)Ym=^{Dh*9FBEAHhPxZ59Uc|52Z`C02CwNKtMEq6-EDfW z)A$7Je4fe&HnG46zAK<*+V|`OgS;KZZmxlkoHaja7bm{f!VI&-0KT-gh3vSkES6aD z`-W}E5Vg500e~L>xBTQ4wFX<22$V}wVyhqENDF}_T^(z^7|-wUr&I4fc2SM_{5{Qc z+&QI~MVjlDoxg*d88kVsk7!3mVHoj)TEdt}MnO>bQ_HF4obUf?hp< z)CGN|5`sAVL*7f;PC^+BS{D0uhP*prR3L@{61HNs)NQKE2M32=&W?U5)$cBSde0!- zX3f7KQmI)v>9)Pu=MY!7baeX^IL$|YmMVv=M>9+@nr`S{6$3kW&UuZ6zLEI<)+=36#LErC`dF}N;nw!-!-u$jJuhY`OAb%y^_&w7ZYOvF4p ziY{gG7-e`uq0!v7H**YVV>g0p2?M1f?KH~~Rt1Hmp&kD6F{Q(@=p;m3y#k~_WTT?8 z{MGvn782Ocn$pZ#Yx#6tAzk5C@CTJw)NFdZVG-Zf!sxPM6x~%XrcUn~zu{~T_}cdM zsNE+U+Tlp0!i9+H_RD@3bW8XheQFBTtJeu_R9ByjL2BZ*16TErNX|c;=bdELy=cCW z2T=vl09vyD2Z0zLd74~{U55%0Mw??Fcmk9(ptA)|=JcMZ78=wQmhuk2g{YRGr zdnyILAlc@4cuXWPLaz9JIoi<^b6^kMJ0a!yHxm7YD@$g}ml1Ns&x1QXCc_hARc*n3 z3NN!(KN;;3YtO1MHB6Nq3jd{;a;LoS!)p&CqTVE8>`)ZS=y`TiVbBep_T`tPrL1njD7? zdg+9l$xwd)!v z&a%6nyp`K)w%l9|OJd`!EmJo}I`r8NyO0Jqgt#km)BQ`wbBQB@10CFQ;U{*3%!m`} zB7McRa#q6+GLs47xYq;~hTP%?=)K!7?mGc_y&5b^inwc{6lX z@NimjSaWy*sy0yPD2@J{A}95^83OI(7_-6d*;?ovBJX*|7iZRh)h|0p6^)8*Di#Ze z*iA)0Jy}1J(QwrD;r-~MV(Gob9mNB%HVjmWsxWz@Hscm97vQ^6X0FtF)&Y;HI;iBX zROon{QQx1ET0`FM9c318z7KxQ5eqJ!PQH_IwEVF+l|(!q30U7R5VJoxgb^QLw#cg| zBZrF%PzhW1w?YXl_XF0Q!720+L5ItzK#^H;Bj{uFeIMKszLe4A(++v>%h_oN8}f7; zZf1b^85DB*5uWaR@;_bxppyx(!!YfWmOGPuof!mvRf=w=y_&X-My?U!$pP|^OdL%{ zG-l;G`z|lI)O2-USh7~o*M8uijFJImkVM{91)*FhFC zhPF1Ka<{ppcGmn`0v04Qsy@%7S+rd!pKOwaV9`gIxCS`?@{t%qvaScl-E`{p@Nvxe z>dq@`;w#@n-u^BP@*cGK>6W7-HUT9q2%j(Zx6nN4S#3zJsjaQFx4&z~`}+_W0PuLY zRBNF1G@z+`Jg0VX>ZyB0}?IqUYPTY&M5w zT4Da2mh7NhB5`>?G*0HiwI|98DxzlQ6ud+tA9)N=ZkKzY{BNjhu*3-ORPzO1232h*J>1Pp<{;edbKVLf-%roQ(Vp^l6 zD<-n*9ifWv(s9`ZvHi)%J%Vbsu`xbdDjP$x zT_>^ky0gk{6tB@|P^tD!3e3`vEvwW+Tdd_ZP$O$O&$%Vr-#Ba|xX_$+;==AJ~6*p4HkE0;tYjhHtqca8t1 zDQ*^&GcSCD1S^~OLn#c`k}+F8ZS|!~@M9z#vN68TsC!vN_OXDoxI7rQhxVgmEolWd zGU&P(b>&+jlo}lFwthS(R#6a?dnDtBOsplbdu3MZ%GEje9(>MU?MeDDm`If0ox$&R zJ={Z~U%73|Y~BsT(FEI)$Yfstvos8?Z_?`UM-l3llBca{&WJnzxE(b(SZT-;kc!RF;}d8Rj5tTf4=YQ1Aee_;06kw+HiW-&aV{h4oCTn z3Jue`P}1)-Zi$(NA1Sdsblf>L&#{NgPNw6!;&8A?&pBp;tVg#IHq8ZD{qrLHDXq{p z_vTH;JX?{|wd~KJ9m4)jur$;ACrO`wyJ)=?uU(WOoFTUMX{^)6_9jAy+vi64Xg@o; z^0t;q>4V{~T$Y)=CzuU>4DL@l?0wCkH_(eMyn>O@Hcetk!SN@c4|UuzV(hnxtA~#tkfZ1k28ZvK5m8SPJ3cZFm>vGnR?yTLls_QPYT!j~VVD^h@#{njyX4lV+p8re01ESyr17(MB^!uxrm2L)6 zGnoe!k1kVq&Dm5}@wFOI^AKHVxDGB}?aj1|S;c9OhXH&@b<4-WZZz?QMdnL6%;_LU2faTWM zhE4YFkBYvcIZ-BqBLTMu-oCt`{}TIfY$fb{OxwVZe)$04h^X+xP8zAsHOu>4!H6do zncngr_{Zbj9cRVuhrc>GaF?|-0R&r)i^ar?C`NTcBVpKrw4UtoWW^^1XLngGCx^ON zVGdU?yiqd2R#Cvw?NxV5@zZiTYx^4*YNYb?q)cEoIEQi*nV|dL;<$gC6aKAyrt7!b_F_l!UkGnjQQaSC1YHfYO$q0fKAXvhr_@HWTh8M<~c2H#7rdOhKeQY1iuhCEP` zBe(xrtd>81)O_n}nsn)d01O`}jQdf=&Y4DC=_eql=VSmLh%#eIXfB*mgUgM+qrk6I zfo~Tjb7%aCzqF4CsOP%e3o+7|+6|Y=C7oZr^t(Sbe|g1k_ye5a(p%|F zRv7x|z0*2eo=KlajN2a-t-j-bqLz;>ZD)La#O?NIU2$hQe>o;pyTe+nppA2J(tF)8FKr|Z)>@>b=1Lc`uxFr&!$&c-M|`ewQ}F>?QCN{Lb7 z3(1jcXa0nJ`T_SwKP=+>{L%dUSHtP)m-8!gcr^Mr0l$`=Kr?bQ>4$PB$@NDL3*EJX z&Jz!BW4$Wpt9z$A`Ac?RT?z380}AdTt399EB3z9&EY5WIou!4Nph(@FIYzCEcKKH( z5+G&^2RkUzu5q0#i(7crR*Ci2g1%TY`ZNcWEB!nqA&M7|17! zY=N<@B?6W?`0fM*G}dEYJZiNuzbjlE=^UcPbEag+pN@wMMng)!PSsea3`t5U{51cg zerHL}_e92p?pf|1hwgqvp8IMID7SXZMA1yWS5t&gmN>aZbGZvXY6;RXsgGqW88_>v zRm&?+O=>IG`SEz`!5!|Tm^5Ei4~@MVNg8Y;u_HQiSQF~+6BMxQ5s65B{PL3cfI1j| z`2@%88SHgqNru&*))AZf`(s??(@>2WY)ptDtxX!x5Lz8Gs1&s!saqw z>_#nR;{I=`?F1K@eDvQ}rICT>o+y8bGKI!+3=8$S>A-hw@q%&8NT;%gm96_bn%Gcq zgYX$fUn-WaT%DOe@4%!5(f&B=@bD1d85_t`UeS1We5sHj+zbl+(3nn9>k3BXimtFIM6{RF3?70nJQkuY+b>-zYMF{kvnI-qaXm+mj5)pht<&T7CF-UqJuu{0gF3EyyJM? zef6#a#LTvKb8N)_XlR7k!T)l8?twOJ>CeODhAIOFWURaY>BkXI?4QuM0>Sn&p9Pow zAzNgfESf*?*OC`jF3BIBid#O~k;9zPhc-0eV-cjylAZZj0A>s=h5L|`VAW>IJM)f) z6IURX1VXo<5S&T)a8hngZIAHl&-%uYE}~9BenRs*}r;li{JS!qn}UFJeHxOK>gUd%0+RV`xc*eqVH%lK zj6l|on|zhTD~dNp?RUg{bus2gHh7GVu2*r zt44EHg{KW3<26CK%Kw(jIM4vyvBz>f(QcwsF#<+AhQREdi#xv-F|7K|2N*^_;~AE$ z5^D3P=#@2l(SNQXrx)v<*DEFl+S79lOT#P#O`l(m=rug%<0BQm7rzO@*fJ>WuZ2Yq zbm(pHeq0&Q$cd|OFI(a-_Ah;$oQu8|NmvM6PBA4;-cjIG1PZksjPN}DfS zjJ$ig_E68l;nvhW`hj;PEf-9%d>oEcFoFP0>bW~NZF-p04sT048Y>E~ILkklUnThsn~Wa?rDuI5-R{mt{@+fETk zL91cU!RC<)Gxwd*(W{q-7tZ_!C{BZg6?Xq9VL9ecAnQMblOMZ)eAitY|DC$%ue%?6brHN`y^VKbTi4`tX}B*0ZSU7mEc$D+j#pf;%biaL_~rJmv1)<-FNYNg}x0(oJz zRRo3Rq#9x`+#o|1e7q$>-<7c!!fZrZHPR+$Jiysi2;W+{`P?eqXwE1ahZHzY-en|9 zUG}>lg^PBrop0#xL9o@4YyE2W{cJtn13=O>@F#OtSN}W>xBtC4bkaj_az)A> zzk7UEocvt`dZ{~4>)!n@Pr~xtyVCkqFW-V+xRigA2!?-@Ys$ftEpOCacZRyjW_`Mq zUGRmYgd9o*;=u_SfRK zktr51O@U7t&FATX+Ph~K%hr4yiSy()6`)Ts(_0EY^U6Kl(G|5`jx0h7@ndSAd*a8c zZ4IaA2=$+Su@VSAE@z7f2-Lxsr>^26wQwlJXaC!onCXL(7j&_cTUy=^_v?MgUHyL= zitSb1UHcLXx4-_4W&!ZSC6ypb*6pns`J?8{=k3Zcz#s}$(i0oGdg4>TEqDruK%Sua zMQ24VdT>_Evxb*QYmL87BSO;M2YUlnN}3RglC5J^X-fU__L(S|NoJ#WG2$L{hJ0>a z9d%>5(ygk=*|8wEFe2c3&(Ygy>g$lK9oUw;Y{393iY#5pN?n!EV{qW03;xJV(Wt6k zeopfC;LR=>R$h2{>mLh9b+>o`tB_xLW*5gWr{_|VSR3a>LUqaF6Iij*2EE5&8=BPI zfNx%MnPMp$)r7w0Y&R}WC z9=7s+eInng2ATNV=N2-1u$c*(^3@dgmG3-~H9PjXkt> zM^SF8{>T)&+mgYCEPseBzRWRXoi*^fH>G^Cfq1|4*8?z%f)6g|;&>Xs#H)MFFqI~X zYG@=Wrs%b`V1UdH;&wQpK&KzmjA4s!G&(^Pz8n5 ztWV2*oL-YZ!#Gs#x6WF|PTJ1xBS0?Jt3;jiGrk+n!(O3b1;>_yhfqYkr2l$vK71^` z%S8GM6((;&h+1S|WhLzpAySRM8_1>J%bA7%nc|$aoOo-?oU&Gjh^o zRK!1>s`GJ6TPx9*#rpqRW8Sfl;`o-O^u3bqzklgMU+Ux0F)?v$m>NPL-He4P=r2eO_vhyPY0j&PrB)&oQ=G`=0c!P$vFy!!FZj z1V)0IBHYX$r!_t~ds^&v5j1x`Qjfd}Oc=hHI}G(!(*+1=FZVhLzhMa>k~kf2qPb)a zr{Y%sPy;Z#Q@xSKw@)XKr1wzS>f~qx_1vrQY$3=y;h@3lQJ^B3qezPFNsq6ymGh{> z>)wzn1!yTAr|hP^UnE(ewI0#i?t47>!OM+QlMi>S@t*`bF?c=w_H*1Zg^amf($1P5R$KKC99#p#EgT8fHs4>}y?Sro-UzEVLdh9N&wc7G z`mCv}-1dpA?IFKK^zeQ7vU3?3cMuAIKA4;Dw~Z5T5fbCVg{NCotYs>sHhWCK*!Nu< z)wHztTrZd5WM8%touK1_zk!o~a!UZXeMj`i8 zrVlr|P|Ykxy#F}K#l7+pxY+eM0%*eH5haDKxL4B2wKc^kx&ba?hHM*V!djxy%iRWn zOS&^dF$Q6nh3Ok?B5q685SIaakRgb0dyReg=1;LRjnfF-gMzdR0-@{z)vSgo3AAPG zj&yz>G=ImmiKE)=2QzP!TyM*21Dy`(*?%#4ZVh)xfXZCg2+PchQ{DIFjZaEE$m-A! zSZ37SYKs$*yt-Ky*k;3Mf<;+eo5U0}7;e!TVWJjjg;zhrXTS!oFX7^UD>~f^=6V!F znRuR2p2tZPm&z2nu|6V*@AK@C&izfL^B@ zt_Zq5?`|yi+xtWPl69qzRCgXfEzhjI1+l5##1#xN7wCy|-lAzE!Ti<>hPHpb*((Hv z$}LGIo!`AB;FS~Mo#uZIxlv5^5&go>Qu2dm+g4_~=i_Pr9&PXWk9+7|h1RoIt!Hf| zE}>mgH%=O?d!BKSSIUfAn-d@Ot*q_2i{50ouH(F3wU#pCJG4;!Z&++Z=;Lg%ec-@1f5y5%XpUC3JUI#nQV0)OI@zZ$=)Mh%_$!nJsBJx4N;XXh%Z0VMrN56FN zQmum{q3N=lt59eEdnUM9emI#SO7SFnkVtfNcGlSOJE|RWdf?T42~LWH<$_E++e#t> zyRpvC)i^zECh)o2(jglU5agG>nDBPQRzjR!OhMgvc*?v^-D|)#c1J3Jgu9W5AcF|4 z;HYD_DqNtq+IpIFuyFY}qS$p19zSeFay&jd?rT9|$;X!a9K~9~ zf`Gjx2zH=SF58RBbPd33o zGBA+u9IV<4(Zx0gN+5=E%#0-^$6u zH733b{4>sNX?g7LB=2)GX-a4?FnO)C;lUzCl?k4bRaVvz}_WcM-#aWnA z^H2QgVCQH{iY6KUkna)FbGNT9UHx)}5k}?rLC+H(o-1L;c*8O@#*mWAFZyd7+QM$W z%y{B1-2IoCP-cG}&KBZQ!WU~{GaEH3=2!}Pd5;s4%zrOZ?}f;7OCr|3FtP1iIBVu; zmPB5HrVR8_IBxjvofq*m3IPByHW9CK3ujdv1tqDLzE-+a-*{|SZ`aw;#-54tW=Rta1E#Qv?i%|tcl*+&#Gn-l||^J#;! z@I} zUw@PfA}@87xi0TAt_m$AR)sDN8{KhtA35wt&p-o|`}4Nl`xT7X^!GZldPAt41GUx_ zNS{W)f@2)^O9x$Er*^bL%Tk1o%k3E>zSBzi5)gCSSNPDBHgC^6(3E&n_>`b6`Rqs| z?#}b?BhzbVtk;+{oX`p;Zd(Tgsx*EhHfjS<45hG>AYqW<;_cIXlV4>`b%Rs^%;%_+m*6+jUDH%t6 znD6$ID1M8Z*gy`(@2~}A^IFmwnBp*OZ!!+Ra6CZ+MiLfG_3>FEPnb-S*Io(D+ z69Q7voj=6ndS{Pj?HKmZNo*ZRo$LXw_up&XsN(w)lfjFnz*wPr@bSxxuihg8sN;91fuE*j+O zb03qG!NVR-zwZe2S(BO1Q99E`gn&g2Qt`QC9gqzVnGZuy(b(M-ZK{XggL2RQ;G4Z? zaU0i!y`4V;#Fo9b&(+=_Gw#2W#Q@B?7Hr&j^$2LKc3aRRIHL9z2q4dAwoM619%_XI z7niu`+DF8ERgnN?sdjfhNCiurS>*4~L?2PoGbIg9!w)`_-#YRF6?G*14z3}lom;bR zgNr^$M_r4(L2&{=U1i^8wOEwl3e#4wqT3CjSX@%WM5!unSS^g-sC|ezRxxSinvhPp zKb|I>^Ma<%HL4^5Udxkb&o4RBDMX60^~*<=2wO@k}HT1TSg@ z_6niLcr~66t?*^CLRJk8Oa5$WsIxHO80POE&knjx z)_xPoD)v~)?q~MhMODZ146pxIY&WB<0u@ObkW!wi$8Nws|zX;cW_j% z@1GMo*in=?fFd}lFYlS1;luNfJ`HF_#_`)#G6+>(tezY{Av-~~=FhBV#FZ;8U$^72 zw*3mLw<1Ek1p)~X*KB8N4&>g5%c+kwR6lq*|7&GsydK`wYCJJgmMJGuH1`Sm#5SBV zFHd*6qYAFda*I=%|DZSJD*w4QKT!yr_s#x#@reI8NPGXiP{x;sa@l5fV})M{>#?C7 z`o+cx+;D#@Ll8n``sRZ?D3H(0j4aPUu$`oSr{JaTEeH zy&vfPW7FPfY%c|nrD@mTBdDh_P6*zM&uzYPQ*-*Y*$Vq9o40M2RXbazN&b{Cny-_G zTzHk@d*V5R)j80}U`3{H&bd6bi^imOWEogm^#| ziGR9D{yZ{T>-wQ7HS4<#**G3JNs#quizJCu?q>yj?I*plZL&1LbvSvSuQ%rA=MJga zR3FBqFb_Zok&`$X&g^cOB5UCoi}XlM$}LX?MU!v>B@6vE{}Pez1tXb*yWD_ql2;Am z8n==XFk865O3gd-cDPsgBwEx-dCywj&;hHx)SPU6==Y<@f{9IVacKOq$fTfYy@+LR zXKW3H`_jry8q0MC1Nw~@ijyIC=?S};DqZ4=J)@BhgUrwa`mR_84%{!+WwHI=dNT2q zoT2uPQ2ginUMkvWQ#P6BFIl{B&Q>u~GrNtn8Z?YQm&6f{y`h7@c!(2w>bVvGrqW7nlp ze7??MT|)%j0MMX+Bzw&FBmdi1FQ;Z^!S!gZVtSYN}Nq^`8vi9Jy?kZSi>s;nVgF>Jm!a z6SDkXMFr2;5L^5$I#Mn%kYpAKEsQtozqpFOzoRrL5Kj4{O*N}ce5{W3V~nN+%!$<|x5)LQ z@1sEMGBmPe@?}`tZC-SQ%9;>^Y|(r6o&@{b7b*->aq%Sa^!@I{(vvddi`0TwabMI_ z?v}N-v(|enSB{BU+Hp+)5)g8$<&7<7gP3qe))-#UPM7qd#lNokKbx;1z#6$tZ<^|B z4GEXCBN{Dh{l3ZulM^*gHe`$1#&$yaB~AY;XWd+<0+eKFjX&S&t1Xyn0geyFY_nNRhN= zlRIn>*ws{(8Q;lq{gXjztKPZSk;SH{kk2}8Hw=R!#0+c%4QT+h+7u!HwmjHZ_Wztd zcky_=?Pe&QT0G)_r|Z2!KvATk_;slv+PBrJMH(UexiI3dNFVUvYjcGOAx4+7H`qOX zR!cydVJLAFEntSdSgR#wmU%x0TsptTY|v=`@2hK0i{B9!aXf}u=aKYgxeJq}ii}h5 zkd9DoMaE8Bul`$)>M22qOyfklx6SX1?$Zj_PHF6%rTp9CHbOK229<>K*p~)dn*!ej z?+}8Et^ZJ4?FEUKfs4QJ>Dq(-wzLyq{I|<@-9NDb03_cp1WVo!f_%rx`zm|lJ(}q& zT2Azv0nL6IP8z*=MpI`^J%}@ zHpua)Vy&A^#iukb)^(vp{w7xu?w*=3Zc!{?@~)_?15>>KJ^_?Y{N0pXeP1*n$DwqX zUPvJ@LZvBktk~dgS9m@kYo?OT23$0kZ2)LRX%zW)@&wp)Q6C=l19V-=& zTv5Gdeg1yjJhb;nltcaE^nW9g&DT^ApHX!}M=;cEveVSSx#M4wBtQ&fPMNUUlj^xd zD}2{%LB=oQwl_CSq<^8nCPdM=SCjJyGg<;zKnCf1fe5aNuWC`#)dd*O1Cm zsLP<`n-?n9Y&`MDwf)_r!jbggm2%HsjSl&nwL`JSVg3MTUF2TY`i?dL zo1HrTs32g_SwQ+Se~-|`$QK~c7e0pKJcdaLeVWI_LI)IaJM@lfn@6NH?cM0t7M3Q+4V zLe~kE&-lXZrUv$JWn@VH*CjsjiZ;y`m?Z?$)~?yag~)BN){FgJcJ+_`IM^hru`bs+ zlIv*a_dgkF5J7iS-V)k-u7BN4T-CcBA>Kbb-0^W0Z(F;FkqN-BEpg1IfcEd|XlYV9 zPIhn)-Uw4uqyhk$w=_`GU1ra6nh!@++9nfE9u15S4` zQWA@vX_|-{UZ)UE{bvI=LZJUuONTrCQ%tXZi<~czvibKZ%}){_COs-#q{sB;X=g?#7_xHL*iNtcqt+i(LPG zMg0BeqbtctjL+D~t38px1$?{u7bZ*eTb*~iDK+1kj}y8sIZmNsSzVyVJaPcHiH>+W zlGTE+J}J$Ng|Pjzx-8lEr|yr{l#ShIRcw940`nYVhAB=6Fp5<44BJ6GE&^LfQQRPM zohK(L;Q6von@%9%KG0$i<}j*P<^j9*9b&>^myxK#i&uZymubzNesySdD3WDXc&OXd zWpD9|0E4A}SF|A57Z^rsdWFbxo-1o+Ej-hw&0Ltn-yjvJpSeXbtt_i)$h%vKo~-Fc zy%UoKCh~zLqq>DY`V>m{40dE3Vx)tuo|I+7DK&K3OL3{~)%RoS4gU9n{p&Ag);w>! z3Lsr@XBUd@zFj+C#=j_v|3_wg#hVULB!pS@pc-z-7xX_M|4{!n@j=mdoqh!6{1q4? zw~G7xGf2hPzv|WmPlVBRT~{WQF}+K7a_eIxtI^6JFtGl)J5C9iJlJ~^w%l>SZ}XO+ znD6G56PzvszK8jJq)%@qQZF+~xBdHgs4eT{J%MqZuSEbUEj?(l?l{0VbuqyG)?Ky_ z++1#5xuvWjrjZHhm=_~jATgcm7e(9}AD7+nPtYjB+<#-L7*(Cj&+2$xErdU_&$msx zG#rC9XgV5iI(v^*a8*xd*W4@nA-9U$taoLYQQAgtj_QSH}lFM51WA~me$=hW8 z_?ApL0L-GMdQ;fAhE1Z+LcL=U5!RVhrMK)!;}KLO44CV$AjN=;0N<*`Jvn$E%4rym zv4d2{Bcxfvcv?S!JtO#x+JA;SW$2r3S|M5e2;cZ50U$fUmmA}8@6H`IML2R~ zT-0ojR`^lH-w)*f36UBruI$nZPe18Z{13|pwfaZgnlc15uE`d63)30+-rT!Bx-`Q5 zT|n7`G0NuxVs$(J@}t-nbxrJ#JJ{tulxFNCnKqPJ31@6{TriJma4%cx;O1>`9di8~ z>TlfhAW^aA6;uee!V=ryny`_}8tmOOXdwpLVw%4XvQ&1lVOow;sJWl$`WqFMFXMkB zf>I*wQtrFN{i$;e_yj5=AgTvMe_gbIh`5D464XZe7G@dYf7?HFQE=a zO5zgjiN+%rzpve?DW7Q-TucnGxThNS803c=1ZZDN>?@iq?#@BepX@w^wTogEYcW(CAZ zH0Uc3=YNmS_w0a-R6%OnPjc%wB`d`2D~L^n{bK**zOmxFnCYL!cV7-B>+MeruU7j{ z4Iw(#Libl?0tuEHFqsjxe%bKYd$BRbIP=+_ZvL9`n=B`W2#dwgSll8%dF{>PP%gI9 zj>HDsB1*g>;@YfmM0m7Af%YU+u{BO4fC}Uu5$p8no=jQ^&uu-BA2qT+FCo6vBFi$S z^pDoLmwNQ#q3IZLs3LKxfSA&fSTG_4#1>ix%VlIxjz4emuxu%RC~+Mo>`$!|xYR_fZu6NK+k-3?KM&&^oQQL_n`fWQbj{|!vZ{8EU+gDHb{d>O*he~vVY@3{#qOS z>&sx1^v2TezHVrF?9pRdpk&CgC?PE*YDeYGia0q(+duta%K&?96U8POa@it}Kt&3~IG}I}?8s!+udj#(>7x#H#NFBTJO(P0Gh_m7CO`!HT{l z9d-pnJeOD2ewE&bT(Up6w%F~D9TzAzrFwjgrR`fA)U);Woi@QPl<~xX80w`O!v~)a zrI?=}T3-vH;?0uB9XC2-GZaO9T{2-fbJOwh4q!BoH(Mna7m`ZCb5;Zh5O4v0|LCirC5$|uGbI)DxeeeCBbKbkVR+bepWcm6& z!{_sSp63xKjF%ZlFVK`3#$@^4;$m~p5Q_paDF^0ha(4(d>BWzf<|VeXwyJsc7o_LC ztYG(fEA61Bfm?=kKc=FDZS`^82_GpvAgP@{RNpv(jpC;V&KNDXWhB}=RiS=I; z&fz1O-ff=>yXvRzDrGPH;P`peDfjuR?2A0HlH_k!Alclqh>>Z>9V^E^<%q0%aEC*V z>X&Zw7iIMhSY{3L*?;dr1HyibPj!CBOO-Ipb0wWz5#{1icX~4efYJK}(=MjKSXy}! z+LgVh;YFo#@)LKb@$7#gR{np-jQ{Gn;T+EmUVBFI)48HYcO37q_uT$DYlyKe=lH69 zK>bbZu@{iak$0E);r)EF4zK{o4F2u$iWl>uPcgrGLP~ zneLtlz~1{ph26lRRcve8Jr7He-}85dWDkS-YzR^Njw_I*K%$4FVG)z!-kMbypRFV zFNy&8p;;Ge>1ZQ6OQ&vI)g5KI{2euexwcyySmL4vRiv}+U zVrG9*&a6;|{QzK~(zRLtimCq30>l4|Cjb6qoqBrx*!jqqG@E(6dGgaG$s1d(+VtKs z)YA;TWM$TCF5?RYdg}QT_{;?sR$dI5zi(#+HlUa08*kB$7LTWdEV0L{$QiLnKaOUG zEFH10-c*9^Tr34N3|aE9X7Zv+-Dc*i`1VG1TyL4+v-)1S`->{Ri;9BX=sTtZ3MXu0 zuWkL&Wv_4YLs~7M=9HKs3bKy+oK^JfE!A*zd+3#v zJY>dCNk<1eJuk;nj+;W#TbkF+yl*-?Y|7F!Z-K&21A?#S*&F$OKy-~!MOGA(=ga6`{Aa@SDI#gr3Gi^l|z4dQiZLBQ<q$fs$utR(gAC1=MW06J5OQl7lwjmg!2LK16u~l^) zcB59B5@SXGnVF0mR8oS4L)wI-q79Q?RNX{Tt9}}OWhCNk^vDd1``&!Te&Tl*S(9W)Iq#;}ow^SCnVoi86D-+gG!8g%^Q}Z(>Ro=~24( zE$7P>HrO?PYS(I2;hXzAEl4D=fF<89*ev!|a$k?-x_O%Ky5@+o2x8ikUDfHKXYJpE zB-t(-MrV;UEh@h9clLkHwv#T;h9KwEw>#Q0L&`-%ZFH}KDCq#7U=C;84=0mV;DO$B z_b8hXvNx=^7$Y1b))Yu>_#>R3d-hN8UK^UP@TogT-oKlxbT#!C$@BW>kX3W`sPf-& z0dI0#-jFaLWbf*310hvBStS<0G>B71it4;(H$;t-*)EhZ*tbJ$z-;^ukn;BNzKn{F8>%lVhj#LLq;ts2f{c(wuXK2TgGZAyz5OlLlReo(CE7$m*@)2|nFM(e9s!TsgA$Y=&a^6s+ zbGXlI|20|lcKp7S^ zdm7x_trEffLyGbIbojgbd)HBm$Ks?nf#1>T0;T;pnNyLp)Liv+%IsUEvgjmU`cjRT z!yyB8UbU=Y++lMR=`~POMNfL?-+HEjn9EEKs{vEp3*#s?&Nv<&9#l7hPZ7F&-P!?1 zs}k%SZk9+i2@DY7E#Fas(?x8Jy4&oRTQg5eMAughXEppA*s#QNTUmv*UTOUy4%Yk~ zW}Rsq5aF$l9AOSh5i%$A7p5N_zIv=O&~lpoXz}i`yp9W(*$Kb442{Hv+O#b+u7ct7 z?*v+Hwt1*;5zaxqqSv?isRNK9{cefEk8_F&&mJ@hHM~S4Ij2u{$3U0+Ki^1eH55l| z65WdF>ZYk8kE(@Kh74o?VG4f`7@$g5iUoSEP{+dofA`ErLu}ta4}jOm&MTnl z059uA7h7;dxygn*_}#R`@% zeb~9(+P9ALVe-88!M4B0!qxUyfWFS`jj#|~Ll0Kpqs}V;ACuIv&~X#)bfKKRNT0(Y ze=*aux0*qAw*|{=1dqeF2FmA*(M>+stDwM~1<8o%{-VtAz-j@bLBTFdBpp&>`%#M< zIcH3WN!~QmC3t_3t{N~5$u>m`$JLW>oHYi^6g}<|1nMkT)#~Cm?JNYErwv~ziRe%t zV};dTUQT^?Y`))XDo2!O+Os*j)$r>p9V`C1KfwV`$AbFLvD)U@!o~9NmBk@wb2>6t`H$+~VCL@+jWQJ8$b-VYM}IX!_V1w&B<%Rj*{$qO85yV_ zPhI~7E8;kY8|1kdtX=@wGEB7X(LNwS>_!oaGDu2Sl#Nk$*{y)*R{V4e-Ne8_-hM?f zloQWReBgboqR<6!)8@2%9;LgU`dAsZhe3xcJH$E6$7_U6D`oD)sv)Br{NcAp$cfS? z`Yu^&QZBx}+gnI1IveNw)zDnLQMhCBLQUn5f@WMz2l1ZQfE-QB;;vSnR%!@zFS0=*sih)qoeu7I3jr00er>;hP-v*>MoG?Sz`|25?n>p40(*g|(tsoDR& zH7F2{=E$%~vILH^i{|3BR*;Hn+WSN-nHP9d`5TV2=+J1WB1S%=ARn1CjG0(PeXGBw z#B2XqeuG&bT$k^$?NusbeB+C(%oYzK|EHZAXZXCQyVMx-RYV9Q3P4Ub5?iyZHn670 z3Yx=0cEFAflu}L?L13xQCZ^;mlRS%&uDX7i1K}q7oM2ze-F?-MV7SxUgBFu(k+^3b zHZWQPnwIN^FJaxCjYtB*NpYfLc!h3rQGQrp&UFs44}G4lIoDO$+iaea1HKg)=~ey& z=-1K2EA#lc^JFD1lUa0%(FN6^3uU!aaj+t0`qk5*fX%Bmlyy7jk=H$#LbF88`9Gl{ zi`5p?4tX5})d8mVOd#OH3o$4}c)lwX@Nd>;kkP}cmWDg?gCbzfmIR@U{EWxH>1Y*v z^794nuu2BUKA%y`-*0;K_KIDrzs0Eqz0mwJ%-r-ySbl?s?S%x_kCu}m;bsAYO0Q?= zVPQ87M-KOdf7j`cXet z!eKibgRVSpRvwmczK)2U+2BNzEQw$1UA_J zGx5RyaT?D5{vzq|5$n;j2GA#+US8pQOs56*p*1#-^h7qk!cf!BCy51k=jDS%u6 zIM`#4*Bgxx`2)k}Ki3*b`47pvMu{(teodmhD~JHwyH2_&5{ZvNAgd% zC=INz1FkpV(y?47b*^~(9f&g&=<*lZ0n`nE^_SB9%gMs?amOSD++TMd&3aR12mjV{ z_+p$!5XT!x9RLznMO%`RLF|I8Q3;*5u!i_Vn{YRT2AIkd6u;>S%5&?tyj$!h;xkYR zY))@jzge*T2PSLQ!x`alNG5aoem+*+Ca|rbo?O|+U3gH71zGYfPfs_5=htG!jnxRF z*NvaOOEC!`d8Zg{85W~cAmM@Ahm{K7cV4q`h$cBb#|Iqf&mD#W9g5yI4W90nV8`;f zCeM_N5HtM|Z)?XP_~4$4tnwH5?Oi7`muVO{TqCFoi z0o9iT>MD?-qPj~!*EG4%1VTe1V#gT|P7i+MT+c$2R@W3<23M*3TS?RlyIZmCMtHTUqOK+$K=ZuwT>gu{ zHMp&=P}uXl2%FE#8+Rq1t^Td=GZlH8zboIe2uPVifQ`^RK z(}eKZv-HSog0y(3vF&AcwMR7-?|31N~wwuhB^FOfz0+ETWQuQzf0TQf$MhfFu2 zaYts%hadqxx%Z=`ro#SaOSjik|9JK~r#XeY4hsElhmQY`ehl>M88^_2h>_vO&7ND{ zZXj1{aO$)7di0JP<59r8aQV4L=Tp=rK;yVqXseE^i3eEjX>aIrTPyzgIkW)6P01#_ z;1$iStTqXlPrLU4s?c}mNiZ_FTWt}Y79pjq_Wy(1`4`9ezkM~(DR`dw@c55TP-H=r!&vot)&kpJ3vPj|&AsO*HpxMuI5IFj+Zi2*B zK)0U>Ia@M!<^ke-jm!C0nzkp!%3nKV;b_ERdo@0hV?H$(8S!F?0@uEanier@o|lSW zGU`U7DOtqCXy<0?@s@Ee_`IhG;{!U(0kd-o7?||d@13_|wPppArUEPHz4Nln=oV0& z*?D6RM*~`OT=1Z+OZM2~hoeunHy$+-q4Z;7{{M|y>A#?U{wH}9beSVg{eU>w5MuE; zd3@X33*awL)EjYwGy3r<7mhMWi^)gFoKnBC9vAU$#k;ww zz^J2f4kOCGUMe#5gosB#+9TWb?;YF<4|4MIzf9NEU?1OfFx=ZK78{QIp9k}Q{UqP{ z5Rm+22s*MRuK8WJ{rvd5E-rjS002}a`3pM@WcfjXixo!Y&#%5|7Xy@3AftW*y* zxoKrIUro&O`H8uy&Y+2aWiAv*lS{3xpgOOD?jI3ml6zXDXXL+-hs^4f;xRegKDBl} zT^fSVPs4oxx@P};NwoknfqCv@?c1xDZx5G#a#fXytd(#uanBdvt?{{VGxSlVxh;R& zYo+4o;w%8BcG%LF_aiM0eU7EwqHkP>BXLV<;D}D3NZO80tp8lYH6m)s>X46h>w%XK zVI)ZMD~|xBMK2Mb-wcc;1P1&euC*S;60f40&(-c+zSxqx4fhKFi}%Lwfa6K6+C$R0 z^MNusw*py4W4bFIGtGN{*AMlzP&2A>)D^HbC0AB+4CX7VdN0)VpxVc*7GItM&p` zcXT@7MM3?X{!4hsY(?E5BGH+3-!%PpSKJ1hvbeTOk-q0kvu}gDPilI%M|!o~)JW$3Ymc~6jmjFTRRiyi0aeto7t9a!?+(BA7 zp^?$6oZ>S}kcP}vggBU?Y5>FBu!>kbX4||?PcSfkC~eby`To>fp?zeN81CeaHzr^? z(ANv6dyjAcL|ukWs$>~>Otp$A#XfOVtW&l-nRD6XB}VK0>{mN)IWFt~_Ez#7MsM-9 zcsQkYfjq=(NA?zkM?*4qjIF|^g-wxxC%l~lCV)9}DOun&j*Ol0gvAh*@l*$(uc}rC z{bnxj$wHdF&bcRVo9Fwmq)qp`$A7~e#egGA1_vjkg|MIA3^nfz4jCw49&L2YsoTi* za@ZZGx9wV%F!iBY^kIX$-sbE*vG%REA8lwFJU(QI&@jO#oH@$q4OpCdGP17P5;({y zoajLxfZSSnhI5zR-jGW<6kb}4?rPQ=b&JX$Wt)?S>HGV8^)?=AG7ERRSmO(*?ZA-J zNw+h@JQJeI@5|M2ZOZ?Ru2*h9N|3wLaErnnp9DD6NU^BrMn|Ycl|0M=FB?9dn?qjB z)U=cg`%yzg!nCG_Cv|``=9g1iv zqZR3H(x=|NUrwwD5xgTN93xkEQ_Ah8u-lbv@8^1|DzT2vgE!@wkYeqdwixa0YK)7p_K7VA zdo2-X4jQHoSep?MjFy)0gSK68*um+8uTJ!%ElLbl!CC}^RlEjcux2v8SfxA9fzsAs zzI4Auwdk;ezTJuG@Tom?^FdZb8g<`pB4TI%$wWj2Q*5yX=0nf>whO1TPwf$!4=8_s zkS;isE@Udy;0^zIvj2TnbjUccM;xuTA-uRa69wC2h#VzDhXWA!*uz=Fe)#Y{gUlfDI*g#pyA+%OKbetGdGX zSW&w`fy0=o=#ay5r3_lCv}+UqBrN)mXvLhUB2Js8Kd9xRGzfRTBfxQr3R`Tig`^$c zIH~OK)OTq_Y)-0tAHHyM zqxo)VY4BmV8wx-hp7;+>V@Q4bYF@h^Juu49(2|5)3}$FN#s03NQ(tMpO|CPb6}Kp! zh>rQ?j5yYrmK!|5?lT+bCa@npx4_N0Mc|KYlj7Hl&RTM>C0VK0(vC|t>$lMN_QfX@ z=mwn=5r5x-iU=0DF!X>qS7I@zo6O8LW4)xVfj0t9PO#7JVuH~$VBR<1+lYe?jcUxj zPX~ML2m5meENVo=9xH0C<>8hxi%?CiptL-Vf`xvJERp$7QzXrt# z#~)+zGX%U4J@0Gk!f!i_ghY@-&rEzUAbSJzgdrIZ?>&}ey38S7I9H{?xaFc$6NTvOOG~8vOLtD+a|gw%7pv@-H`Am49KYZOBiZj ziINdF0X)l7;~&Fcu>&PFY-+-=wyXSG)J0ONXh>B=1r!bm_VTZ~Z=@!DC9&?Ub58=7AY30vOIC;-5}MNh`% zIsD`n=4|o@xFk%vAo%Cuu7bwiVthfyW4ZT`E07}yX8rn$0=L(evzUDs#R>l=Qcp%> zQf&%g6Z6O8nm4u3udnmZ5k!-lyDA4>1*$$hbus+mVy*oH3#rmi9?n-1;$#lXl9V%a z-q?3n*eAX44|rZyBr=D;g(6p8Ps}$mqAr^s)}+aj`Y}IqigNL!3@nK=h+NAR=x*IP zdFc3vneN`VOo-k&VAhaJim1I)E60(4enhP{mtF(?J%`e?XNuG#J!oDxi;bs_5T>TaVyJ(;KkQ!8q`uQK|%g7*e6@Z+4Vm0PsY zrEWc{L)K9(Lg&}oF7iDYfoTUbMZXofU9`$Lu6535k9o0Lf2p@Tk zfy2-;s2WOCv$I*>R9p%+u)}1q2p{_>q_c7!h;sh2HGhZuBm7|;e8+wR95;}P1j>%4 zl$9j62tz!fGhpvnXutneOWE-7o<`p5MUK^PHJZXI&Ew-zqx9~xoyAMES$wXl2qjlC)GbUDRSJxRGbv_FReKD z6YrjsylMGq-n6Cn60qx|Z&8)zo!ko#M`h050 zJG4^L-15~{EeKBCh5gxY$R{!KKb#dzzEOWkJ8^>h= zSjm8u7eQKQb3qa{ee!L7^L)Ii8e33R;c0dHVwvaZ&m-stM*Z_ki7uvs$pZtK&Iq^b z99DYY+RN6Y;}XztwJUsA zOyb1E6#h*DDjihwTu5^fh+)TrqTgo}I8`aHbeZs%U&q#3gq^j7@HRiUg~zBkaI<=e zN283?Aa_N_Mzf5Nb2k&Ac9MxFkIyCfrdXlgIOR@HRRkMFo7w8AELR5dihhs5(aZ_HqH05P1ohXD4wmP<7Lvt zcBm0x0S5SxOfAoBDm47QKs-i|l5H6usRTkYoZ_duKutqR@Hr1_!IgAKrrUk>8_DL8 zCkVc`t@YsQMJRR$r5)Wx4z>)yn04!-mM z(&7#Znx2Gwrs%J237$yi8elV7M=8oZf2nM8x7SP^ckQV8nbKDzN%xn}FGIwIw7O+Q z6%S0hqi(q8ygz?UJ^eku)+O`forMqRAFJL={K=u5Egt#OjQ6DZQ`!Fdb5B2bfDIQK zCl)I-JoV2GAjjYTT)wjwzW=@XLsMu47-QH4rf2D z1nh53c(T{E=;hn!qRrPVjC>$NG$mKI3q@RnhrO2k3;8lTz^?(_Zp7x+Z`u)?Wb5Re z_T(e!w&>0(+<5iZ2R_MJQb?soq{Qr}@lId5jHvim@p1i^t{$knsdZg>JtbKOlfl|w zaTjJcvbECerI8^>A9k};@z7LuHnTRe+7J!HN|K|Jv`X*=_6&Jlg+}^Db>VJB-lRu3 zIoYbBMauf+BEn|Nwn@sdO9M7j&2I5^V)R3d{W_yv1;N=PH59ztK!}J`=ZzHR`KJ#9 z-bid@OiSx#=}%HL`$isgk3-fyYyvGaG1gv;!4H8zP$Oc&8Xfznn78pVm@*}YXjh5C z7tn-RsmL%-a=O}1CHBzxW%cg>Fb>m!`0&^v}Q#_kj8GCFTl&nrys z?qE_fBwX3@XZ%p?ex+PQBg^lyL&TFXkcxfXWLi#Xm5>>w4W{SIz0&d!p z%?NpUfZjix5%b3}4msg}_IQXtsi{+G_(_4TQij!dy0$)2AiL27MYMdu$L_OTPZ64+ z%2&HaS-WlVb?EM|(_FN}$K+jQteQj+Jn&$DgLn(S$0nhM+CZ5DG9&p!roUsLJ24dmSNBw@d;laGqbanJVd8(+}pQ&w^c>UJU zS}T2#)?f7Wf)#XTK1}Ic4NLtCVSx9pUre$>v7Kx250@z3!vCq*V#p$;S&gF@a#6jV zBqlI1`mcC{mC4d0p)&)y6Q9X1TocE4y#GEQi{EuVPPfyTXuFxekh(GJGA+4AlZB;m zn8IR@3byE$=z9U!Vb}O8hKo=Iv~Kp3 zI?{6qtE=&78=nztv+t(+!=?dJnTd(3Y*6+JgPKy$ivA_~>P-?senmAYq1_5+rejjz z?~{N4?Om6`9c@G+b))Pxg1VAp#=(a{*U$oi&bD`aueFWGmK!!nU3tZ=<XOCYEJg1 zqb&yMkdnN6XS1s!(?f-;eOV;;%qv4FMIK*GoHqT{*&xOb1m?i)lY|&0mOo53(!@_N zaQDMK6n^NL(B%t$C}yQL?9l*`SeZs8g1`a7++SmZ*6x$zO?-W(%{-2pZ(9iZ8GJ8i;qi)>t#wsIqnk!wY-+k z-TcXNjdd6qm@>676&mLAf|$Co&)O>6fWmUk1`*z2!Ia8j+b^d_180YA;FPh6r~Fze z+nTt{aL!qI^}4hEdO>JT|K*an{)V=gu+d4sU!A_#E{`xIZno2J-m$$e1#}W$3Z|C| z<=Lz4ID92ryvaW#jBvNPB?HxG9N{$-t-P|Iw|-5AJSZ-O_(8B>NdoJcI7XQwCFPJs zx#dEavW5=kOCOS{f^2iiE$#e&b@XJ<${(yz(*x7q5~o>P3}wIm}ddh+1IZAYY= zG3hgG>g?*hN|uRlySSTAb7^jX8A@Gp)@e@oTGmr#9mvdWHre`wsC)<#spHOeXhYUS zT$Y+@G;dtN-?Wir3R<{eJtM2g1@+f?W(|cTn3&r5^{q2(P~X!Hf!fLKOn)Sz|BJ}s zhLB0G=_qMO|D5GPA-xW+4BghS-)vsKmnp@*$?OUm8YA(#;24F7JP)kev8oZ#Zzof`RmgB<Ow3?5>*YF zrO8)wg}pv_{J^C_yriX-gZFpXS1jO}H+ysb!q_2-xh6)o#$dBt$8Z!8WBildvp8SM z!{S)|mCSEqiP&Vny;@7O5W-C~;OK^2IQB)QxlQA3DWqEw(6d$OMUa5sWh@u_PMh#k z61>Vu)nN9Bz_ea3wC|`WCzv`PV<}iz{ZSHe{d+`UR@L?KuO3=H>$OUciQ>>)by{S+ zNtCJ&quroHF+WX~OY34~4PH=K?tWxVCm1etHvABO6KkD3&}Q1Qjld+W!^C;L0>OPT`!Z2{i?1rEu6%k*0X z`Qcotq2j4n@zy@Yq}m082+D&|^?^F>$-`N82@(zC{QGYr&?QwP4 zTJtzk$z6W@)b9e&#y$QdOLQJGEZvn5ytJ)|@khot@wwF>8G?~aa5Xwxm-Xt%+ih$7 zu3_>;^~9nhvEay`*-xJ-k9Qq!%akY_ite>AE z4+|Il1|%vNnI@nb@%VD8AC1mckU!rX*-&~nK}hP#U8v9mY{nVRp6) zuy6@)tBQQ*ez8!tsNi`^f`lVa1B?7FGizSA0z%cUICmng?=(sCR&4pB-ZcrS_;GvE zb#CmSyf&ygsjwj%z}7#wGN9`FQvVEy0yy>|_rGD$FD1JwWerzj04&PK_RXMV!7)rX zsedck$lpiqF@qt{g4p40B~tHD<}H1;yC##91)agmE<)`7K7ezw7?symhTap|ii^!bM((w_4sQZUc_L-x9A(Jgv zhAt8$ssxdwXl*ZG1g$bRc$BkdwthzZ9Bn`%vu0apz)_u3q}WrKmYSsCVOaA z>2D@%VW@+(be{sAGzjI%=aNH+CQgjER0cN_Yg3${ZsI3kqB_h+w^D+@Hha$!7*voUk{24Y#dof0{_&6>h4XdZJ(9 z#cdm=Q|aU!E@jUq_ZzO!jPQ96PQD4^R$tQ|?=PjV5_%ma{70ZhU9=Ri)Gp`icA*9- zBkDOJsKD3Z4QhJA492VH9*THF5WFueQ?gU=ZBrTMvmz-6VYv?t0;6YP4zKOeqB2 z#pM~Y&W2+bH7Zqqi%S*<$icahb3F$S&o$RRnK?W`+RB3=x%vEL0Q`)p-}AhXapep)vJS98!tVajIfco=eG*(oJ;9 zG_a!&TO8yvIGAVbm)SFPLuE|rWvQ9h!(34M_S=HmoQcL!*BJ%L!1-ZRf=-Uq?Lo=J zaZZ8!9O<-$2nT@KVEx<`|6TV5a69>qX$aub&`f=&Ut>&s93rI=J-bXFg~H622yVhI z1DA~md%1N7rjL*k%07gCWnukzXZ5CRtlj|Dk}aFwFA0~VPo--F$>ZmV!$^#@a}$t8 zA|6!4!e(>n8!<`jenvF!i*eq^DtI4es76B?6B1mH&OX&iw6xtIwGu0@+X(eRm@kWU zVg6hFqQkFdT}|WZ;$If~`~)zYM2H@6!ko9$=wq~JGCG47Ua)S5N(pz;ZVP zRqKAz+FBR4Uu~xc6dZ8e`R8;X04I+94JW2@kvjtGD@KjUSOG~xDLa}1+%Z_EVUnQB zV5I|rV+Wv*QPq|yO*%UyW1O3{JX$~4-=)2ob4!X-@7y0Ha=e0QTonHeOwK1T4qdP$%0=+=Lci4S{#o2O|OeQo>||wxho(9OZ9i- z;YxdwqyZVY{1wgRYL$y(Amsg$0f@0J*)C1($VRxIcU}8cdIZ$8lL#F&k@hL^Wy~Zd z&q|Llfo#L2(loAum6X0AZeJ&$T5#}njp7_~c=)&YV*W#`pO-(5;bA+(zwWXMCTOsN z+r5}u0mPVG*ss*Dx-^RXIZN5r&8L4eE&tw$>c*P;I`5s){s zQI-1lZTfEIrWNXQDiQHv{A()Y5@q48@{r+Dre|&{Ho?{K!ODguw-*qqAtS;Z*~2*! z)h{{>QwB^sGAiXhVt;1C^O|-#PQv_yb-$5{bL)J4+EAOLsf6<_jKmh^+W3>HuQ66| zTAt+-jTUSAKgSuyJijD)KCI0>0q-qZ(xQYkQ1b_@?S=nZ0v?^%cE^`#TJtH5xkU0LiWo`uU;F`h$YgFiI3B`%#Ayu z`mJnYA^y`MQCxb;TlReV56VTdVPYsBLC7clu$Mq3;;cBNq!)skufeAO3HZ!?wT|9Ldyi8SDh1ePs? z?h?_=K?ZPS(5)w|orCRPIX~g>WWNLY)A1(u#Id`~)5j77z+^8{529U{&Tw1EXG0?P z1P;7jxmVFoDyEn5%$EbDCZ=G)PD z0gYKaw49LzDJ z1(Kr9Ltt9d5}crHR7$3&{2W8x3`b(FFAa>4o=k@I%UfFbZV}~)ao7#2iAR__b)geJ zttJND&W_tSXO=1@f{eNnZD@2V?hqyLB&jHh6v!@YGuUXuFGayP$ryFyZw#+jzKE*t zz>nwLD__sNRsFrww}C9@uTLPJkZ{y~)LTtbQ$Wq`YBarmB1oI&9Q$&Do^URpe5&wX z*ans>3|kOzQpk*-cCa(Sh=G3&T>R0r#{99y8efeOcQzLP=arG@R+-3Fh6`#p4ZI() z97c zuM3*LvqNjMGC^N&NzyUDm|e-$r0O^Aw-;;WDV~SYC9Xd;ZzrBobY~|yo;oaf9lW1_ z`F`m*^KZiLFn)OV=rWQPM`qazqvBOWOe1#1U$+khC&}&i zOHS+`qWw6vBRpwa0X7mw1fMV(@IE6~%uQOc7SU>m<*Jm^`m<+K>PS{yy}Ap< zEbEFX$*FHoIjkR^aMIH`6`-{~niEyD@Mh@YmTNJ$PDhRaJ*go!SEixT(gQVpbfV>o z8|nep($9L1CXes|PA*zn5-aECq8pxW;I}msC*!|TdZY=Gz}?{5iG|YT_9TTs3@O-_ zxDkCQZhW(@AegcYp9o(IwOx7p8vrwqjj(a}A=lf+fa3nc-PtECTcIuc1k`fExwkD1 zC-yi!!!WjlCp4;X(;g?;%ZFnC1Vp~6pKyboz3jy!xT`!{3)fXw#5j@&%Nf z$hlu&`$X8-v3=2h%r*dr$HCzjzU&yZ7P=PtWP;i5XUOQZY+0W>hdDs?ChoJX9&xGW zo>(K2;IE~f8=!T<6U)nZQnCs|HtN^K3${*7*_i=HzR!z(GNjkViYcK-E7Mb}?To>5 z^Jmo`CB+CB>db4F=v3oDP_6r#;)q#om{txQqvn4}3OD#r{c_wE|2@d{wRzq|S?zhX*vw!NwrR4<>Ewbx6qAh*%lBT?T4R2GX@Fw5km)r2n z^;u0pXrE!nRf~$1+05YTPq#Lm9FoURtR!$BWWs1|aS?!3h0nh5i&!xD;)mLDv^w@X zTwY#eYv{yQ{@7pRJ40ic5xWDHEv#)kD|4UM>OW=yEav8n*I6zSvdwF-4^ne2uWnA`KL`JAdWU0_*R0MF}CMwRFH*%bNK? zv#mlv0&{=Qwd zGp>lfSr0*9O^A-ssQq6@9|RG(K=61F%=^Z7d%Bx06f)6d)73%;GMhCg)LgpVD!tpT zr7m=5#ACqnpVxZi)<0WJZqDrm!B~YtkT~&!aSznY;x;#!)zcZ_eXeNdQ9ufWbp=0tESuXPi9kHq#98>E z{9P=CMB*UOvvY%9eUz)3Fs&8w&{iT-TcJ)^D|kyjs>a-R^)loD()BWLlhkkhhVU}` zu8n;@$g$0lV$t=Y;SxeDDUwC|%K76L&$C~bh%>gT%da;2{L~SD76>S%Vkdv9&tj3w z)0wkx7F$SBAcK8uOdJ)X+kzdG3K%VlN-e~5M?5IM)3lNKtu}ho!t7yWI(~d|o%L=# z6{2jmZg`$FDVItbsMOBaTPF@PY2647H2SXf%!xSWx{s_}i&2;C$_u{t%^X&!V4s0+ zq5FAT9e zeUtFT{rK;2l*{~)iQ*coMzlyF3MhDzHC9}3Kv_dAJ5DhB&cy&gWo>CpzLmw+G6CGn zS(LXBS}j_}-{-}E#9y@UaJMbqj$P(DqaP6`1fAGU<80`VxaRTwcILU#+>P~fT=YD! zKab-HNI$|#y^BG9p{F=Un?fW3rBp?b5hBmB zKGZ#VD&~_ey+#*bQ>>(r!k?eew%kH$7vj|rCUq0)Nn|wY*?l#t=qcP;{~UPJvx$H6HAk6P+L2O-?Wc(0~r6_x!qO=IsI$ZZ7~pcr;+ot~iR$`l9}8e-a$NmHS08 zKe(vnYZY74zpO(3_tYc6k2^>3tPk6bZ)SX=jBl+zDfgR!v&Q{cc`e~{bD8k@ii$9= zb1m%)xuMPYg}pExq;ZlQ*$_NuJG_I4|PM|6@-Ok1Kgs1*%QU`{B=_` z^94eAB&BR694qvwZ!Iz9k5Z*PM%6d6lQl`z^f?#}E3{9uWzj5+7(`pxK6O=yH7WE& zqmkSYYxP?IpU@%ou>ivA{#wMr&ahqc=A1_O2DT!6W#A_Lpl-Cfj4oi*6ncEpi=uaa z1shq?S7S=ZTHBI?;fA>+o5=%S-k{md#4*~)mx4C^^*FLefKX(pY7H^Nkeupm2BY+6;sr+OUm(lD;Ojt^p$8#Xb!~f5s zPm5OQJVvK4MD>Tj35J}wSs+KRg}{S;?K-irq&R^$6+uY@M?g@4hN@1`{3XM{*;e#< zl3w%fO;C1SB2;*1@S_Y?)+fQknIb!FJQ)Kr2y_8>=)^H9u5(p%xuTMZIlvJPro+WG z#zVe#|$PmQvNPzG=4#DFMT?g@rJiCN{Ek`*JlYSyymkuBGw>3Ky`(rjt5BmoGq#&RFs9 z@_ELo?Xmxos3tvVVM7LFfenBOVBAxLU-z7XbAnZOu6zli&TFa%(Ig1xzyGxlUc%xn zzS@A1%N^qqqs~M`p!_wz3%Kqqo^OK##s3d$ZyuLa-oB5wP1aOeIg^?SmQzkoiO%<@-MOeO=dmz3)@(#Qy%x;(L|)VC}E=%aEySMi<-I;!Y1d zDdUB9eaa@FjW*a93FM5Z9n$zLQ@Pu<6t3&ix_iGnI#-IT5Ghl;cYZ@=SB#|5D#tgF zA!9lsWt;$rZ(%gEu6&ke0S{`l2i@iTWebS0Z+$8&>BQd6*{d6?Ps7 z4NhrBt(S3#TW62{^YrF z8(Uw}0$+c-WuA3zT?h3WZwV}H6~VT)KU`<6N`BT@-S^_gzJj-iNm$>>u-3onaR_hP zY33766K0)W87>Q*W|6gyNL^PWQlH^RPZqb%$T7*}#Lul|QDH%^{s*0T%*$nishXkM zwmjKKNZ&e8_kuJPVFJ5ZWL+CB_-m8?yf7r2s2#e#i0=VjsQXlqVtUgu*6rGhCGif% zUteso#_9p{@W+;?yk5K6sfG6nPId*E#d}+5RAR!_FW81LFY$XvXMH5@NE!2tU>a~Ya?5lsfQsPY06z)g4IocCD8 zymc@1f00Qs$CriFB}Hqv9u3i&-m1D}p7@T;2P$!<%)~NM!8-w=I}E8MbnK^_LGQ=d->pMkUAXSnwfC?2yR)|6q-Th>F33cU-hxzE*JbcJ~op zx$n{-2KzBh+sfXvbi#soc#caj&pTFZ9^Tj8bH?tpx^Iuz!>S%`Bp27C`-~qWEZZEB z2CdVuAt$lkPz?WP35?VP%`_1pX+}Rht&LxVxBXw>CeCk5daGo$q?wv((#Ma(m9=Ey z=ZfUdy9xpt%H3Jyh*SflI||Agn8hb{@MBnbIIilwCE84A0Zv@dpLtrOSKe;TUyhQTXO!!d~U-gzq*xH0#e3qQCmG z$WQ#o4aYLv)P7f{k9(8bx@%2yth<4EYGu>4*=UN`XFy09iAN6 z4C*_*Zan54v&A#4d_%H)iPKGCVC++)&H@;78ir=m(Q`+fIpEw0_>N!wDEXKs;qN?~ z7kb{YZPB;?cL`lP;`oYtCo@r4PZFhB%nXBFzJDc(6EGFM!)wsP_~7$a6No+b1GQA0 z7$AZ@1p=nzBhbK<6aee-?x|hg+|Fx*hix*4BFE(;A4$`*rw>`!tia(NMZu|aqI7e{ zIZ>5yV7#{7TwbyqH&tjsTGmcIgiD#*0Q)7|vBN>a^%u~v`)^EDlzu%kn`G1Mp^#QJ z1+Pp|_NKAWJ?m;CmNfMoxt62k*n$1I!AVcU=Vp5?8m zwP~_beg~fGyPr3Fyn~o?j*7X`p1rG2WRX03(#+zu?LlBn8(0j9&tzG6Hh*ynzH@_^ z>G#OaKD@z;u)+Psls0o47Nbzk7=%EI22}86xj+0bn5oHQQN*p* znPHM_s9v586M|~frD^9<2hzw}D`;#5!#K@kB#mY`m#jxu4G;nffE!m*zql~_DLBO= zr%Ulmo$w<+d((ik>Wpjr0KPF%J2qEKHnv|Xw4;!*l*p;>o@be<3&vp!%p<~~9Vsn^ zonNDN{RoWSMskW|*ws>2B_J z3ZOfCjZOafx?`(8UufMHURJeq?vo#E*Ox3Mn(H&npyv0^35r;JW{hHhL+Ce7c@>#d z7Cs;z3(WG+AVk^`N?uKHFP#ktqLXHHFh<2xk>qcm);t%q>f+O$4 zTRfBXnOfFDq7TqnH#qidlROf(CERk^--%vu)-+vAS-sc=Y24Iz;o zQtrouRkIf(Xa&dHFHM*C02vl;Co}CXDubtr65?{*UON_tDr%{hTzpa_&3!MQ+1sSt z*GVW}PJJWUd0Jc*3Y%?_VZZlW;O>Nqsy?NCvg5v49=@x6-VoTlNqHz2*=IezZDl^x zob8A8aoV#oe02l&-SFWJO_yPbpcA>w^9s%7xyWzRx?SAT;%BM6dB)P{IS$9$J zMa=(1SMc3)GU~Tv`C}#>)FV?x(f}j?QibK*$m6=v^PH-Ivf^d%Kbb^s$VeZAM-o2r zuOV5L|G=+OHC-xqEsaSTm1jdMo*ocioT4lpTP@!Jwlww`7c{psQTUkO%eJd`V$`d1 zh1TQkBR=o*sdTNfmkHY)V_sS;q{Wctuqy?#|E9SRC}D>@<-{MYg` zeTNiSn%m0_O<ZR_Sp?J+uUcaVts`&qIJzQOF zv&fmFeD`6iG*g|&3a!@<9(1nPf-9WsX2G%mdX2vQ4k45>S1U~Y1TW1fs|19;RC+&6 zjjw<=wG1z4$dnk88`9Hrb*ZQr-t2b`@eFhyEcxX6YJZ%(E$^sjKi}YtCudxx340=V zNpsqhSZe1g2iK+SXW4~f0(L>dcNu-TFhPFS;aNZ(zP25PZ)+O+v^T71p3PKR#SZmJ zmNR8`ARif=6zkfsWzG1pmOnPfwJ$0BYFB2SA8Y&DJ<4X~RkI}v{{6nqH6cd(r&FHo z?&lTmDa*XW)*|2WhXeINTPvH-3=QZVi=51L*|0Rx%qDC*wRp`(-Nx7*yA{?(BAvzZz-(1Ws?S132%%Bin|RXCG_p|&%Jc#iN6HbT z8cIzkOsS#cP$KMei!;d}p^;XPipa`Qt z&r&g@XhSbhVmfZBfbgkZ`YIJsDvW9o>Vel?3O)q8*omAA6ck|kpdj)&D3cnL#L3%4_uTm6qVhvuFv;bfq%rQ ztU>PmMK;NUArFLW?ZX_>p1O4ivL^aQV^0CRsSljIv8RcPSlQtrm9M|d za39UK_x#-^03c^PW>ktB`87qp=u~Tik)va>)NsRa>5Hlam6*X+BLq4tUhsxRwqKEw zGihIZTfBQ}!GilPxr}uY+u^NYuk#!FCa{rn_i*1o_h`W6s;mzhcMV0}ffWFSXvL{w z^I_zV!u-X37FCxm8}!F-;e=9Re@zEF=I{ZO)!qo)s2xNK@wwY{)ny-s3QWI0 zC6p)DZBE{PUxK+84@Eb{LGeb+a8+mR-8f^vXtDe1RDn>064&7$8L%2;>C+JJm!=u& z)n24Q^x6<5WyQyATWcXJQ|1beejWmHs^d)4kaT^cBAo6z`4WzpC}X!ijT9+m_2LFC zLWmX6AdA`57{3`cmU=W<%6HsRf(Zs*a+N;$k}R)IS}(E$a~vp#&Kvvnw+xr0CA|!T z>UL6f=O5{HtbY-W$xRPc1SwW{DoK3qc4MB^LrU37}g0OW|~|gwYXT9onx`Rf+QfF1&s9Q<04=0+ch&Q{_c_ z#+yZhO*k8LFMg%;LHhF>4ArYxFdz0G>Q@(3H-G-HfoJAV3<#(^FJ+ty{j`D0giO5xAVG|OGrUw%3_ z-qaGaY8RT{#;5F z;7V77+P*Xmg1R*6zs6LR^HG-b1=UPeW#>2q1OrJvN!d}x5BjGns{r0GrvkcQ9MacH zEMPk!paS2f+;H2-ThzoJxxa=srr6JCpa3=4uc#6%W_Z;2U!1-;h2lmm*U!g?=MEqD z`OrEGN90pDXk>Iu;0E{<1Fzihe8$HOY@;ZpRw6@oDm-{2(+B`ORvPVj_cNaay;dus zbea$uoaSOQqWp64zK&EpizyCyGR-PHnPyJHpK_#zBJrmp(8-dk*$Lc}D^EpiOM*B5 zxDRYkP<&>wzSkBNsH{n0SB70uY#W+weBmB65y5MIz6r5}NMY~0MpK-a;(G6At!l{W zD5B|ZSQfbKBT~5IOlm?i2>8SX7Q2hXBXcI4O2-|h?>PE0snHYJ8B~Q^dID2)Iwf^u zSIOE-2Y#X=zxZi0&FjlW+sNZ=9`#!1VC+iFG-@H-SPe+0$#dCT;K^p+cP{;sG*v=m z+n&l?d6{YBhl!xY-iBSg>)*qj9A7jEY==3zh-dxcg5+w*wl11j;#~2)D+aHyOxJx% zUlk7ZxOgd~)Dlm2x)WXDg#Io*c9>hBxLP%G@X#{M=xPQXcHZ`m$_ey`@H9`TNuIRf z?suYp35e>xV!!fMc1UUC*O*a=;b82W$bU z66@S{(L)iDYF0g;mqrG6*F%m{eJ$tOp~$+NzC=?$&bLl@@$exw1RGR;!K8u)`#GTT8v19ZciM{g=tX%N)p2GBuD?DQ~Buo9sg zcSQ0tTD)JBq{MWcxNwP80`QT>^@)Hq?| z>uL&pL3N2AkWwx7*;|V8kqG)%5~=*m$n3VA`! znaHWxympKt(8ArdRF`3fNoDsO8wR=fEOVgQI#PcR4a3aiHjPs3O2t-8#U>=XvyF%j zdp_}&J^y7{Eqy*!uE1!guI-jk7vYG`>Tt$V=_xc*n8)60@P2WOf_Kb*m(FH!K0fKb z%ZRGjuQTIx30xxI_%^*+XPdM>+%74sU1(-I#cv~S7qoE(%@voO0c|1}4@c01{-cp; zAWAKc{ZPU=4j=?AB^(mGW)Z-NvHUU#pUxqfx(s>4m}%-lVa=sgx~Z*$;E~MdWC}txtQLuq?ALTBu9=ALc&+euUkA8 z+-0Xkemd7oI5g*tBdc6YYol~Ge49J?+%;jAw;oy4!!F|fdpICs!!=z68!hT8U<`v7 zns#@{0*!?nU3ThIh12FgFm9i`B`i9E6qS#RFR(-=kAYBcd!Uappz5~*dkFR`P~O2? zuu$?(=TQE*F0R>f6@dvkWW`7qea?K?i*{kY0cg4^tZY;c9vBX)e#ip7sOCiJEu z6FQe8yq67=VYH$sX6_kyRZxJ~#Zc_qzmlic7YVFrRtLti2o!FvJ9qE?m0Ypr4;QWv z^!)WOY>H-XN9`j<wGs7zW&4w+9PqCSaQ)L`PX4+^ zj)>}d3R_5|!R6>TSmfsn0cycgSw$8MUj&%2cY09;%d|V^I8Xs&jko#FnQ$(Ekw_J! zwm-l}&L;pi$Kz%1nfD4mKC%u_-y7FGl{nKkc_OApQ0S@dWa5cPK4V21eATa2zgGnC zaVWr^bz}a6uj?)65MK)QwW>s^OymhClIWo!JqZZ8Sg*W)P6)q@dY!t&Ck0xNfl|SF z2L1wG#6CXKKw1`HCfhK}lBhf?6t#OT>8wxrHs(wB{b<)xmJdfsfc6ew?*dFc`US~Ff+iT{% z9xsY0?hI6pX;@V!&GH5JNE7TGQ(YZ3E|e05)64{D!}qfGZJlnB5Hp8U?pco6RYaGT z@p6*N)H=fvvy}DUrFJKS8v@epo2)kuzuzjn?P1_Gd6ao$iD6;8x7<8ZesUz8;(yyE zLHjM?8JSJ^evi4Qi|B?~Sfu|bdqY~9z<$5Dh<6v3tWG>|Rh{%rn=RTir>&9i4UTb? zI2Y_RJ@!Dxug^o&D1N?>&5f@+#D6d2T25Wx^Q;H#5hN*Fu?kmoMNh)xQg2|+8<_N> zVP4uKuBr+Ym+?Bu%I~ftYA!49AXxhK~HvSY;r} zkZM_SsRrVaCMQy)af2}Y$m6xjb3VdP1oE?I|AIFH=zep>i+{jujdLZ0HklYFj?mG> z!knPfXID5^Kx;FM$-VFyoh3^oKS`^|MNu3cn1{|-@&}&; z-&)yQ-M4s)pBWWdfE>?e`hS`(Sy->0)vw`emAMV-){aZ7bOgKbzI-ahJ+gvQY>Q#*mAX0XZOk;>A-9BH9$6fuL(Z?4&VUuX@NWb5L@vMcdBEB7bIPWn<;LE6_?;Cy4i5G*f^ zck?^`rFC)V_#~gzcNGZNPvo2Igx_*1@XozVUG@)lG4Gx=g5uv9T2bcqgj~qb4dKYo zd-(dti!pdCE^Ke#tAaGTRG5{{&{>fjPHS@;1AAZJb62oN_BUPW3bvBpF0MWOA~!f; zH!pYZA3YoGTwRhjXQ5ELNKT)ugYUCPD!So~4k?l`YaGS8S*sj=HlA_HKjOrLlKuLi z%u2YPjonX{SmWHU1ybcL2kplT8^bI-M@noFwqa*s;jo>+n*KGaLJ@Gvf&CoQ!6Fk= zpPd$Oa!(L*x6bHBFgTSieZIPw4&V%i^m#TD z3?TRgy}}YsFra~J$lvux(2D{JQ^k|>rK-0B1t3^!PymwQxO<1*#Q5UP(Tozoxv%k6NM|$zWj$HvMV#ZXL>JmDlHt2)ihliRQ42 zqqBeTM~@Z=IzZI#Ozy4zsb6GsGGwVGW#-!gW0 zo^9rR@>bvlyTGZ5zwD)Qx`*>tj>WBXb{D@9r2W>vHp;V^XdcdW!8EK!B{XMXk0jj3 zd8%j2b+#^>&8Op_-W>B6?&Nvp56(6`RB6_v4Feai&LC}5iX2{GwaE1}XcK8O^^i*6O-4HFuCmm-lbL;moX`mu_ zM*`s0KpOR|)nErVkl+-;oIe%(NAwXjbdGveX1g0bpIMx!>BAU%*4Kr$rj5gx+vFu$$|%q5GGax-LV3qoW0C?f~@lS7TxxmE60R zU*`}fhQV<9^@T;QPWU9_nN`l)bk8z(ih;zm$t|&iJa{$#Bp8MCva>1V^4qb~cqx&|bEitFX zZ^-jA?~c7(VET=k?N*$YPX6{AD!Tcbh(h%Evo)UkWM3?$w08SOE^x7cdZ$95Etl&Q*aOm1hb zM9MePQ^vAXr?Sj3*q;=|#pV%}=-4hxUZ8Sv_EhAI^m8KJ)l`mh=BS4JDWe^_Jkx*> z18R7n*KeID$Q#NLToI%|iGPtDQXL_|Gy%oFgeK?HigeLFEWQNh&nn)UTfImgsinjR zh~5@&LWM0woB;S}QzCqHWAei8p1-9#HYcDQ@(Q&)4u{X$63zt(Vvr6<`68Fai1`ep zHsN?CVCt_bmAM*KG9Op-3^TWWpW@)W#J8DU zP%wY+tO3iv6CY^T`EWj$0l6xT&)ra|N?_2d=C%rQBG!X-5FfM?j-TPnJ07hJZ-qHe zGT*`CN~leAJ61Lj*P5qY-BSnm@$Tx_0T=8>V<>xj{jhfHzr&A8bah(<816f4;TcLK zv+$laA33C&yTunKh>wqEKWe{!V~@6G3s>9gq9{H>EVWtDuk4{@Sj0qbKGqi^(|GjO zL8qv8HWi*`DdFRheS7r|RToYxwK~HNb;YfW&{|25MP`BJhRR#}%##*Hg>K$V^`|U4 z6&c>-^2qjI3tnZfyHFbVpwS{n`0&H?GIZEa;(cbaz5(T_NCYggZ*IC8KsA4HA!*JP zh;6SqzJkpxOzMMm>R^g=7bcoOkvgrb>`K;kL|_p~JnfqThKt)zV^=PmhWfk!^5)L6 z&^edQR;%bBD9*x0?BRd$Z!P`DOq6yK-sE9x<=spc?{`-?I_1c-x2#iW3sh_JJS{W9 zKAN~{oxTSg+raIBznI!K2ls5>a6~Kx3l>#{^U_H$ERhYc%mM@U!jdWnA{vKaf&#B0 zj4nhPWIZqr0}4it%q-|gP3ffZh>S6x0+_=X74%qxtp_HJJ<(C{9~{>`TeI6;Ose_+ zyaOLxZPg{N`k4a!gGZ7mN@%*e^uL^1TWo})hkC0_&ei=2q-0JtV``OXI87>00(~+# zF}8NM^%MxDP7OXl7fg5QE-viT#yz2`@v~j!Z#x6WXFr%D?Eiq1bWGBEw_O&IgO7fN^5e`zQ(Wj$qJ`2xJ?&mMv00YKIJ+2Z8Nlu<8t6P#bH$qsQ`SM&OY zzI#XnN!47GvG}Ep-^Y&G4}g|${#opFjWXJ3{U-EHs4-cG6+Uy}njg0K+V7ee#4veoa>H2oH;Z?=ShrJf?yB%cFXitju9> z^h}46dr2UGQglqDT=h0oDE-XPow37@V{woIFl7Y8DoOIpywWDu_p3BX(_?iDEM@?> z{#0M=xTjge+JN|PfOv)aR#U!bO0swHt@tqU@tb-H;};ma=!;bW^9mZzZJ$(DCP|BM zGW0TdZof(SQMw_$;R9hcs~FbB_&4YrwQOr$f*MSofA|Y{%*R-ALj90}7vxiyIG_Qe z>(bRQwn^u&SG+8G2D52mXOJz0BTIY+Q^v;LYuO5p)SbO3i0f_!~TBTX5oFyOir-*@)R1OH4}3Dx22XM%d!6 z_?B>p7CDzYyD8^NM>`eu2dyTTmWQ)@wnyk`$`|fd_6XLC!5jI=k3k;LxRJ(=ZJ2Gg zv9!QQPTQs2_ndV>#PHy2a6K+x-FKeqJSN)}y^|T;&e2q71BVlAO9>&{)^!ywTe@zg zEc}b3HnyvuTP`7uX;<6kv!}W@q=W1}auFsb5+3hDJQO#pePtWLwv}<0Ny4{{o?}rf zUgj^+Jx0}>IfTE*kbe`oVa|7agg{A!?IU=CYhL{NbgvFhU$#HK6J*MjE<4!Qlk0Vs zZNh~(MWb)lh7|lL-sgPr(q-_EyBLzsuKOcu;>#zx?&)55KPC>5UmwHdl zr;ho?4Gb`h6*nTrLa-Mvv`1{x22}`4j{57g&G`u}m?QZ@21vX7%61V~;s6UO540 zB4LWDniEicx6*W~9{9#0Jk-zwHnTKfoA=EgmFY36z`71vV>SwUaQL^>O;>om_m#m9 zwj*OA+ld|ASLScvUBEUyq!-b%Wrsi7@Q=^ZDizK*{tVu1JCa7fcR~D00CL%WXoc(M zYfG?p)7e`a1Z4vFYH4!2i>jRMdw1&yI8ssU4P&wT;G&elgHz`!Veo zjIvzkxaOnJqR5c3$?^iPX+mgHYI`H~@piAV;cv?Qa#qz}VX((5y8Yk{F#gw3j7 z{U{!l-@0D&e9pN8>hV+-K1D)26yGZUWxtHv<*V&>P!8_;rvFd*n1&ZM(dzB3sm?JuV?(i!aX;!1^9aGxPe=p}|4=KkU_I03_`QrAVy z)U8W2qUc)@t{yK<@qb)kqk4CJ6xi1fvER3lSVadbD z4|$q)@b9*rMvwt#2vUSpW;DqE#t)+EM?S<3l;Eop4mEJTKyZ3rv4=0##teiDM)vaA!FLb*Dg|n(KxnNV3F@I9K}c zdAmHaB{V zoi>7l=30&*)dNKy z7BR~4Pd5|>ZzqLyT6JHi5Lo4LA1(HfO}XsHt{iB$fG2Lqi}Qtc2bBXE-($YDY23)) z+WeqpQ=p(=b>;YVQO<+67j8ZBlU!T9r;!J`?ohAxlExjfC`y}kHODKq`uVwHeBABq za*dDcy^IqTSF7B?PaoEN0=v;V2S5C`FU!UIP+J)P~q))_cQo2I8 zXjOq{Zzq|F4|By%UPLJ2sW9NdIITT9UHN+0b7Nv8db%BN&Ta2W((V+laJ|xL? zemh^AqRU9#s>?o%gJxw~(KD}`l7h87<T?) zE-~2Fj((3Ud^};-(<8r}b}*;KRa82%E)$-!b8ThJCqjYzd4B93k7=8p@_hXCUHwk0 zQBUUaTaxbMf+2nzM zx7oT}_DGK|_am4mjSYA`;%vWviMaJuOxUikqFyih^i6lZnXS|Fz7A||;a3=Icv8`8 zYe2Mt5E)`zV(uMzec?H*MK?cCETHbbQ1~-}B01$hIzd3-;puiUQ%xqtFk_Z@#eVC`aq9#JLYz71ri+lc zHVEp`***mg_*LzVCN7V|I|NH0aOx-%7~oEa{L^|D**vrm^v;+_c6E94joH`7Ie){4 z5>5?94U*KfWl7H|bM(K2FBCva9Uj+7w;}#c0h*WRc8m`EwcOg7tHTw)$&e|3tv*Nj z4-~bGNSlYB=P0-4@h05BQEA(o++Jv?1Ywm5l5a!UIo1Qm9k#)sl`*6t7MfKV3}rK) z>|PG*7kf6vW(tsVIy;e$$*DMG3kFK7*DR#jTD9}embVv2?(V~uCHQ8 zxpHc9ix>(&31~dQe%(uMrdjE%@oCOiI{SL5tFFu_H39oE5spjuW!dn_V^^$$&G6D6 z_NSeBRzK!$a_fqENxa~H^9}8u+^#tGfm*!oPtS9pz4y6rZZWe+@x?ds-v&={BQWt} zJifJ%ohA+TDRx9tGVs>U^g2cqe1YQejH$j0)Su zwhmF^gFPeqsn8%=>ozuDzz=!Dtd6`~9 zamHyVRt=krG)X7oPD_o#RhfV!Mª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

TfI71 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 F{|jFJ9FPD2 literal 0 HcmV?d00001 From 5cf96317f2f3f33e7bfa2bf7c54a6fd879cc35ed Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Mon, 5 Jan 2026 06:57:48 +0100 Subject: [PATCH 11/14] Revert "feat(node): structured concurrency with task_group and parallel block download (#162)" This reverts commit 79c0f89872dcc8236f2a123afe44990519c663de. --- banlist.dat | 1 - docs/design/STRUCTURED_CONCURRENCY_DESIGN.md | 383 ----------- docs/parallel-block-download.md | 567 --------------- hosts.cache | 645 ------------------ .../kth/blockchain/interface/block_chain.hpp | 4 +- .../kth/blockchain/pools/block_organizer.hpp | 3 +- .../kth/blockchain/pools/header_organizer.hpp | 14 +- .../include/kth/blockchain/settings.hpp | 2 - .../blockchain/validate/validate_block.hpp | 21 +- .../blockchain/validate/validate_header.hpp | 83 --- src/blockchain/src/interface/block_chain.cpp | 105 +-- src/blockchain/src/pools/block_organizer.cpp | 8 +- src/blockchain/src/pools/header_organizer.cpp | 49 +- .../src/populate/populate_chain_state.cpp | 2 +- src/blockchain/src/settings.cpp | 6 - .../src/validate/validate_block.cpp | 128 +--- .../src/validate/validate_header.cpp | 316 +-------- .../test/block_index_bench/benchmarks.cpp | 2 +- src/c-api/src/node.cpp | 49 +- src/consensus/src/bch-rules/coins.h | 2 +- .../src/bch-rules/script/interpreter.cpp | 2 +- .../src/bch-rules/util/strencodings.h | 2 +- .../src/btc-rules/script/interpreter.cpp | 2 +- .../database/databases/internal_database.ipp | 13 +- src/domain/include/kth/domain/chain/block.hpp | 7 +- .../include/kth/domain/chain/block_basis.hpp | 16 +- .../include/kth/domain/chain/header.hpp | 2 + .../include/kth/domain/chain/header_basis.hpp | 4 + .../include/kth/domain/config/parser.hpp | 7 +- .../include/kth/domain/constants/common.hpp | 9 +- .../kth/domain/impl/machine/interpreter.ipp | 2 +- src/domain/src/chain/block.cpp | 20 +- src/domain/src/chain/block_basis.cpp | 142 +++- src/domain/src/chain/chain_state.cpp | 2 +- src/domain/src/chain/header.cpp | 4 + src/domain/src/chain/header_basis.cpp | 25 + .../include/kth/infrastructure.hpp | 2 - .../impl/utility/serializer.ipp | 4 +- .../infrastructure/utility/cpu_executor.hpp | 157 ----- .../infrastructure/utility/pseudo_random.hpp | 2 +- .../kth/infrastructure/utility/task_group.hpp | 230 ------- src/infrastructure/src/log/sink.cpp | 17 +- .../src/unicode/unicode_streambuf.cpp | 2 +- src/infrastructure/src/utility/png.cpp | 2 +- .../src/utility/system_memory.cpp | 18 +- src/network/include/kth/network/p2p_node.hpp | 36 - .../include/kth/network/peer_session.hpp | 71 -- .../include/kth/network/protocols_coro.hpp | 37 - src/network/include/kth/network/settings.hpp | 1 - src/network/src/banlist.cpp | 23 +- src/network/src/handlers/pong.cpp | 10 +- src/network/src/hosts.cpp | 4 +- src/network/src/p2p_node.cpp | 616 ++++++----------- src/network/src/peer_manager.cpp | 39 +- src/network/src/peer_session.cpp | 165 +---- src/network/src/protocols_coro.cpp | 230 ------- src/network/src/settings.cpp | 6 +- src/node-exe/src/main.cpp | 110 +-- src/node-exe/src/tui_dashboard.cpp | 244 +------ src/node-exe/src/tui_dashboard.hpp | 22 - src/node/CMakeLists.txt | 8 - src/node/data/bn.cfg | 4 +- src/node/include/kth/node.hpp | 2 - .../kth/node/block_download_coordinator.hpp | 235 ------- .../node/block_download_coordinator_v2.hpp | 238 ------- .../include/kth/node/executor/executor.hpp | 172 +++-- src/node/include/kth/node/full_node.hpp | 7 - src/node/include/kth/node/parallel_sync.hpp | 44 -- .../include/kth/node/parallel_sync_v2.hpp | 39 -- src/node/include/kth/node/sync_session.hpp | 27 +- src/node/src/block_download_coordinator.cpp | 360 ---------- .../src/block_download_coordinator_v2.cpp | 411 ----------- src/node/src/executor/executor.cpp | 575 ++++++---------- src/node/src/full_node.cpp | 234 +++---- src/node/src/parallel_sync.cpp | 376 ---------- src/node/src/parallel_sync_v2.cpp | 382 ----------- src/node/src/parser.cpp | 4 +- src/node/src/sync_session.cpp | 396 +++-------- tui_screenshot.png | Bin 1232582 -> 0 bytes 79 files changed, 1066 insertions(+), 7145 deletions(-) delete mode 100644 banlist.dat delete mode 100644 docs/design/STRUCTURED_CONCURRENCY_DESIGN.md delete mode 100644 docs/parallel-block-download.md delete mode 100644 hosts.cache delete mode 100644 src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp delete mode 100644 src/infrastructure/include/kth/infrastructure/utility/task_group.hpp delete mode 100644 src/node/include/kth/node/block_download_coordinator.hpp delete mode 100644 src/node/include/kth/node/block_download_coordinator_v2.hpp delete mode 100644 src/node/include/kth/node/parallel_sync.hpp delete mode 100644 src/node/include/kth/node/parallel_sync_v2.hpp delete mode 100644 src/node/src/block_download_coordinator.cpp delete mode 100644 src/node/src/block_download_coordinator_v2.cpp delete mode 100644 src/node/src/parallel_sync.cpp delete mode 100644 src/node/src/parallel_sync_v2.cpp delete mode 100644 tui_screenshot.png diff --git a/banlist.dat b/banlist.dat deleted file mode 100644 index 0e5abcaf..00000000 --- a/banlist.dat +++ /dev/null @@ -1 +0,0 @@ -# Knuth banlist - format: IP create_time ban_until reason diff --git a/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md b/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md deleted file mode 100644 index 55effc3e..00000000 --- a/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md +++ /dev/null @@ -1,383 +0,0 @@ -# Structured Concurrency Design for Knuth Network Layer - -> **IMPORTANT**: This document is the source of truth for the network layer refactoring. -> Always read this document at the start of each session to understand the design goals. -> Location: `docs/design/STRUCTURED_CONCURRENCY_DESIGN.md` - -## Overview - -This document describes the refactoring of the Knuth network layer from "fire-and-forget" -coroutines (`::asio::detached`) to a structured concurrency model inspired by Go channels -and Kotlin coroutines. - -## Design Principles - -1. **No `::asio::detached`** except at the top-level entry point -2. **All coroutines must be awaited** - parent waits for all children -3. **Channel-based coordination** - Go-style message passing -4. **Separate IO and CPU executors** - maximize parallelism -5. **Graceful shutdown by design** - no race conditions - -## Current Problems - -```cpp -// PROBLEM: Fire-and-forget coroutines -::asio::co_spawn(executor, peer->run(), ::asio::detached); // Lost track! -::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); // Lost track! - -// PROBLEM: Race condition on shutdown -if (stopped()) { co_return; } // Check here... -co_await some_async_op(); // ...but stop() called here = crash -``` - -## Target Architecture - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ executor::run_async() │ -│ (single detached entry point) │ -│ ┌───────────────────────────────────────────────────────────────────┐ │ -│ │ full_node::run() │ │ -│ │ co_await ( │ │ -│ │ run_blockchain_subscriber() && │ │ -│ │ network_.run() && │ │ -│ │ run_sync() │ │ -│ │ ); │ │ -│ │ │ │ │ -│ │ ▼ │ │ -│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ -│ │ │ p2p_node::run() │ │ │ -│ │ │ co_await ( │ │ │ -│ │ │ run_inbound() && │ │ │ -│ │ │ run_outbound() && │ │ │ -│ │ │ peer_supervisor() ← manages all peer lifecycles │ │ │ -│ │ │ ); │ │ │ -│ │ └─────────────────────────────────────────────────────────────┘ │ │ -│ └───────────────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -## Key Components - -### 1. task_group (Nursery Pattern) - -New class to manage dynamic tasks without detached: - -```cpp -// File: src/infrastructure/include/kth/infrastructure/utility/task_group.hpp - -class task_group { -public: - explicit task_group(::asio::any_io_executor executor); - - // Spawn a task - tracked automatically - template - void spawn(Coro&& coro); - - // Spawn and get a handle to cancel later - template - task_handle spawn_with_handle(Coro&& coro); - - // Wait for ALL tasks to complete - ::asio::awaitable join(); - - // Cancel all tasks and wait - ::asio::awaitable cancel_and_join(); - - // Number of active tasks - size_t active_count() const; - -private: - ::asio::any_io_executor executor_; - std::atomic active_count_{0}; - ::asio::experimental::channel done_signal_; -}; -``` - -### 2. peer_supervisor - -Centralized peer lifecycle management: - -```cpp -// In p2p_node - -::asio::awaitable peer_supervisor() { - task_group peer_tasks(pool_.get_executor()); - - while (!stopped_) { - // Wait for new peer OR shutdown - auto event = co_await ( - new_peer_channel_.async_receive(::asio::use_awaitable) || - stop_signal_.async_receive(::asio::use_awaitable) - ); - - if (event.index() == 1) break; // shutdown - - auto [peer, direction] = std::get<0>(event); - - peer_tasks.spawn([this, peer]() -> ::asio::awaitable { - co_await peer->run_full(dispatcher_); - co_await manager_.remove(peer); - spdlog::debug("[p2p_node] Peer {} task completed", peer->authority()); - }); - } - - // CRITICAL: Wait for all peer tasks to finish - co_await peer_tasks.join(); -} -``` - -### 3. Unified peer_session::run_full() - -Single coroutine for entire peer lifecycle: - -```cpp -// In peer_session - -::asio::awaitable run_full(message_dispatcher& dispatcher) { - // All loops run in parallel, all must complete - co_await ( - read_loop() && - write_loop() && - run_protocols(dispatcher) && - inactivity_monitor() && - expiration_monitor() - ); -} -``` - -### 4. Channel-based Coordination - -```cpp -// New channels in p2p_node -struct { - // New peers to be supervised - concurrent_channel new_peer_channel_; - - // Shutdown signal - concurrent_channel stop_signal_; - -} channels_; - -// peer_event structure -struct peer_event { - peer_session::ptr peer; - enum class direction { inbound, outbound } dir; -}; -``` - -### 5. Separate CPU Executor - -```cpp -// For CPU-bound work (validation, etc.) -class cpu_executor { -public: - explicit cpu_executor(size_t threads = std::thread::hardware_concurrency()); - - template - auto post(F&& work) -> ::asio::awaitable>; - - void stop(); - void join(); - -private: - ::asio::thread_pool pool_; -}; -``` - -## Implementation Phases - -### Phase 1: Infrastructure ✅ COMPLETE -- [x] Make `run_inbound()` and `run_outbound()` awaited in `p2p_node::run()` -- [x] Make `full_node::run()` use `&&` operator for parallel tasks -- [x] Create `task_group` class (`src/infrastructure/.../utility/task_group.hpp`) -- [x] Create `cpu_executor` class (`src/infrastructure/.../utility/cpu_executor.hpp`) - -### Phase 2: Peer Lifecycle Refactoring ✅ COMPLETE -- [x] Add `new_peer_channel_` and `stop_signal_` to p2p_node -- [x] Implement `peer_supervisor()` with task_group -- [x] Modify `connect()` to send peer_event to channel with response channel -- [x] Modify `run_inbound()` to send peer_event to channel -- [x] Eliminate `peer->run()` detached spawns using `&&` operator pattern - - supervisor does: `peer->run() && (handshake && add && protocols)` - - connect() waits for handshake result via response channel - -### Phase 3: Connection Management ✅ COMPLETE -- [x] Refactor `run_inbound()` to send new peers to channel (done in Phase 2) -- [x] Refactor `maintain_outbound_connections()` to use task_group for parallel connects -- [x] Refactor seeding to use task_group - -### Phase 4: Cleanup ✅ COMPLETE -- [x] Fix `stop_all()` to NOT clear peers_ map (let remove() handle cleanup) -- [x] Remove `stopped()` check from `remove()` and `remove_by_nonce()` -- [x] Remove all `::asio::detached` from p2p_node.cpp (using `&&` operator pattern) -- [ ] Remove remaining `stopped()` checks from query methods (optional - they're defensive) -- [ ] Update tests - -### Phase 5: CPU Parallelism -- [ ] Integrate `cpu_executor` for block validation -- [ ] Add parallel header validation -- [ ] Add parallel transaction validation - -## Files to Modify - -| File | Changes | -|------|---------| -| `src/infrastructure/.../utility/task_group.hpp` | **DONE** - task_group class | -| `src/infrastructure/.../utility/cpu_executor.hpp` | **DONE** - CPU executor | -| `src/network/include/kth/network/p2p_node.hpp` | Add channels, peer_supervisor | -| `src/network/src/p2p_node.cpp` | Refactor connect/inbound/outbound | -| `src/network/include/kth/network/peer_session.hpp` | Add run_full() | -| `src/network/src/peer_session.cpp` | Implement run_full() | -| `src/network/src/peer_manager.cpp` | Remove stopped() checks | -| `src/node/src/full_node.cpp` | Already done - uses && | - -## Message Flow (Go-style) - -``` - ┌─────────────────┐ - │ run_inbound() │ - │ (accept loop) │ - └────────┬────────┘ - │ new peer - ▼ -┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ run_outbound() │───▶│ new_peer_channel│◀───│ connect() │ -│ (connect loop) │ └────────┬────────┘ │ (manual peer) │ -└─────────────────┘ │ └─────────────────┘ - ▼ - ┌─────────────────────┐ - │ peer_supervisor() │ - │ │ - │ task_group { │ - │ peer1.run_full() │ - │ peer2.run_full() │ - │ peer3.run_full() │ - │ ... │ - │ } │ - └─────────────────────┘ - │ - ▼ on stop() - ┌─────────────────────┐ - │ task_group.join() │ - │ (wait for all) │ - └─────────────────────┘ -``` - -## Shutdown Sequence - -``` -1. stop() called - │ - ├─▶ stop_signal_.send() // Signal supervisor to stop accepting - ├─▶ acceptor_.close() // Stop accepting new connections - └─▶ manager_.stop_all() // Signal all peers to stop - -2. peer_supervisor() receives stop_signal_ - │ - └─▶ Exits while loop, calls peer_tasks.join() - │ - └─▶ Waits for ALL peer->run_full() to complete - │ - └─▶ Each peer: socket closes → loops exit → run_full() returns - -3. run_inbound() exits (acceptor closed) - -4. run_outbound() exits (stopped_ = true) - -5. p2p_node::run() returns (all && branches completed) - -6. full_node::run() returns - -7. executor cleans up io_context - -NO RACE CONDITIONS - everything is awaited! -``` - -## Testing Strategy - -1. **Unit tests for task_group** - - spawn/join behavior - - cancel_and_join behavior - - exception propagation - -2. **Integration tests** - - Clean shutdown with active peers - - Shutdown during connection attempts - - Shutdown during handshake - -3. **Stress tests** - - Many concurrent connections - - Rapid connect/disconnect cycles - - Shutdown under load - -## References - -- [Trio Structured Concurrency](https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning) -- [Kotlin Structured Concurrency](https://kotlinlang.org/docs/coroutines-basics.html#structured-concurrency) -- [ASIO Awaitable Operators](https://think-async.com/Asio/asio-1.28.0/doc/asio/overview/composition/cpp20_coroutines.html) - -## Notes - -- The `&&` operator from `asio::experimental::awaitable_operators` runs coroutines - in parallel and waits for ALL to complete -- The `||` operator runs coroutines in parallel and completes when ANY finishes -- Channels use `asio::experimental::concurrent_channel` for thread-safety -- All peers share the same thread pool (`p2p_node::pool_`) - -## Remaining `::asio::detached` Uses - -These are the remaining detached uses in the codebase (excluding tests): - -### Legitimate / By Design - -| File | Location | Justification | -|------|----------|---------------| -| `task_group.hpp:97` | `spawn()` | Core mechanism - tasks are TRACKED via `active_count_` | -| `task_group.hpp:191` | `scoped_task_group` destructor | RAII blocking wait - expected behavior | -| `executor.cpp:232` | `stop_async()` | Top-level entry point from sync code (signal handlers) | - -### DEFERRED (Requires Restructuring) ✅ COMPLETE - -All `peer->run()` detached spawns have been eliminated using the `&&` operator pattern: - -| File | Location | Solution | -|------|----------|----------| -| `p2p_node.cpp` | `connect()` | Sends to supervisor, waits for handshake via response channel | -| `p2p_node.cpp` | `connect_to_seed()` | Uses `peer->run() && seeding_protocol()` directly | -| `p2p_node.cpp` | `run_inbound()` | Sends to supervisor (no wait needed for inbound) | -| `p2p_node.cpp` | `peer_supervisor()` | Uses `peer->run() && (handshake && add && protocols)` | - -**Pattern used**: The `&&` operator runs both coroutines in parallel. When peer disconnects, -both `run()` and the protocol branch exit, and `&&` completes. No detached needed! - -```cpp -// Structured concurrency pattern for peer lifecycle -peer_tasks.spawn([...]() -> awaitable { - co_await ( - peer->run() && // Message pump runs in parallel - [&]() -> awaitable { - co_await perform_handshake(*peer); // Uses channels (run() is running!) - co_await run_protocols(peer); - }() - ); // Both complete when peer disconnects -}); -``` - -## Future Work - -### High Priority -- [x] ~~Eliminate `peer->run()` detached spawns~~ ✅ COMPLETE - -### Medium Priority -- [ ] Review C API (`src/c-api/`) for structured concurrency patterns -- [ ] Update tests to use structured concurrency where applicable - -### Low Priority -- [ ] Consider making `executor::stop_async()` awaitable -- [ ] Add exception propagation to `task_group` - ---- - -**Last Updated**: 2025-12-22 -**Branch**: `feat/structured-concurrency` diff --git a/docs/parallel-block-download.md b/docs/parallel-block-download.md deleted file mode 100644 index 8dfb5a4d..00000000 --- a/docs/parallel-block-download.md +++ /dev/null @@ -1,567 +0,0 @@ -# Parallel Block Download - Design Document - -## Problem Statement - -Current block download is sequential: request block N, wait for response, request block N+1. -With ~100ms round-trip latency, this limits throughput to ~10 blocks/second regardless of bandwidth. - -**Goal**: Download blocks in parallel from multiple peers to maximize throughput. - -## BCHN Reference Implementation - -BCHN uses a **centralized coordinator** with these parameters: - -```cpp -MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16 // per-peer pipeline depth -BLOCK_DOWNLOAD_WINDOW = 1024 // global look-ahead window -``` - -Key data structures: -- `mapBlocksInFlight`: global multimap (hash → peer_id) tracking ALL in-flight blocks -- `vBlocksInFlight`: per-peer list of blocks being downloaded - -Coordination logic: -1. For each peer, periodically check if `vBlocksInFlight.size() < 16` -2. Call `FindNextBlocksToDownload()` which skips blocks already in `mapBlocksInFlight` -3. Send single `getdata` with multiple block inventories -4. On block received: remove from tracking, process, loop automatically refills - -## Our Design: Block Download Coordinator - -### Architecture - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ BlockDownloadCoordinator │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Shared State │ │ -│ │ - next_height_to_assign: atomic │ │ -│ │ - blocks_in_flight: map │ │ -│ │ - pending_blocks: map (out-of-order buffer) │ │ -│ │ - next_height_to_validate: uint32_t │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ Peer 1 │ │ Peer 2 │ │ Peer 3 │ │ Peer N │ │ -│ │ in_flight: │ │ in_flight: │ │ in_flight: │ │ in_flight: │ │ -│ │ [h1,h2,h3] │ │ [h4,h5,h6] │ │ [h7,h8,h9] │ │ [...] │ │ -│ │ max: 16 │ │ max: 16 │ │ max: 16 │ │ max: 16 │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Validation Pipeline │ │ -│ │ Processes blocks in order as they become available │ │ -│ │ next_height_to_validate → chain_.organize() │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -### Configuration - -```cpp -struct download_config { - size_t max_blocks_per_peer = 16; // pipeline depth per peer - size_t global_window = 1024; // max look-ahead - size_t target_peers = 8; // desired concurrent peers - std::chrono::seconds block_timeout = 60s; - std::chrono::seconds stall_timeout = 10s; -}; -``` - -### Core Components - -#### 1. BlockDownloadCoordinator - -Central coordinator that manages block assignments across peers. - -```cpp -class BlockDownloadCoordinator { -public: - // Called by sync_session to get next blocks to download - std::vector claim_blocks( - peer_session& peer, - size_t max_count // typically 16 - ); - - // Called when a block is received - void block_received( - hash_digest const& hash, - uint32_t height, - domain::message::block block - ); - - // Called when peer disconnects - reassign its blocks - void peer_disconnected(peer_session const& peer); - - // Called periodically to check for stalled downloads - void check_timeouts(); - - // Get next validated block for chain (blocks until available or timeout) - awaitable> next_validated_block(); - -private: - std::mutex mutex_; - - // Assignment tracking - uint32_t start_height_; - uint32_t target_height_; - std::atomic next_height_to_assign_; - - // In-flight tracking: height -> {peer, request_time, hash} - struct Assignment { - peer_session::ptr peer; - std::chrono::steady_clock::time_point requested_at; - hash_digest hash; - }; - std::map in_flight_; - - // Out-of-order buffer: height -> block - std::map pending_blocks_; - - // Validation state - uint32_t next_height_to_validate_; - - // Channel for validation pipeline - concurrent_channel validated_blocks_; -}; -``` - -#### 2. Peer Download Coroutine - -Each peer runs a download coroutine that: -1. Claims blocks from coordinator -2. Sends batch `getdata` -3. Receives blocks and reports to coordinator -4. Repeats - -```cpp -::asio::awaitable peer_download_loop( - peer_session::ptr peer, - BlockDownloadCoordinator& coordinator -) { - while (!stopped_ && peer->connected()) { - // Claim up to 16 blocks - auto blocks = coordinator.claim_blocks(*peer, 16); - if (blocks.empty()) { - // No more blocks or window full - co_await async_sleep(100ms); - continue; - } - - // Send batch getdata - co_await send_getdata(peer, blocks); - - // Receive blocks (with timeout) - for (size_t i = 0; i < blocks.size(); ++i) { - auto result = co_await receive_block_with_timeout(peer, 30s); - if (!result) { - // Timeout or error - coordinator will reassign - break; - } - coordinator.block_received(result->hash, result->height, std::move(*result)); - } - } -} -``` - -#### 3. Validation Pipeline - -Separate coroutine that processes blocks in order: - -```cpp -::asio::awaitable validation_pipeline( - BlockDownloadCoordinator& coordinator, - blockchain::block_chain& chain -) { - while (!stopped_) { - auto block = co_await coordinator.next_validated_block(); - if (!block) break; - - auto ec = co_await chain.organize(*block); - if (ec) { - // Handle validation failure - spdlog::error("Block validation failed at height {}", block->height()); - } - } -} -``` - -### Coordination Strategies - -#### Option A: Centralized (BCHN-style) - -``` -Coordinator assigns blocks sequentially: - Peer 1 gets: [1, 2, 3, ..., 16] - Peer 2 gets: [17, 18, 19, ..., 32] - Peer 3 gets: [33, 34, 35, ..., 48] - -As blocks complete, refill to maintain 16 per peer. -``` - -**Pros**: Simple, predictable, good locality -**Cons**: Single point of coordination - -#### Option B: Work Stealing (Decentralized) - -``` -Each peer claims ranges atomically: - next_to_claim.fetch_add(16) → gets exclusive range - -If peer stalls, others can "steal" unclaimed work. -``` - -**Pros**: Less contention, self-balancing -**Cons**: More complex, potential for gaps - -#### Option C: Hybrid (Recommended) - -``` -1. Coordinator assigns contiguous ranges to peers -2. Each peer manages its own in-flight window -3. On timeout/disconnect, coordinator reassigns to fastest peer -4. Adaptive: assign more blocks to faster peers -``` - -### Handling Edge Cases - -#### 1. Peer Disconnection - -```cpp -void BlockDownloadCoordinator::peer_disconnected(peer_session const& peer) { - std::lock_guard lock(mutex_); - - // Find all blocks assigned to this peer - std::vector to_reassign; - for (auto& [height, assignment] : in_flight_) { - if (assignment.peer.get() == &peer) { - to_reassign.push_back(height); - } - } - - // Move back to unassigned pool - for (auto height : to_reassign) { - in_flight_.erase(height); - // Will be claimed by next peer that asks - } -} -``` - -#### 2. Stalled Downloads - -```cpp -void BlockDownloadCoordinator::check_timeouts() { - auto now = std::chrono::steady_clock::now(); - std::lock_guard lock(mutex_); - - for (auto it = in_flight_.begin(); it != in_flight_.end(); ) { - if (now - it->second.requested_at > stall_timeout_) { - spdlog::warn("Block {} stalled from peer {}", - it->first, it->second.peer->authority()); - - // Ban slow peer or just reassign? - // For now, just reassign - it = in_flight_.erase(it); - } else { - ++it; - } - } -} -``` - -#### 3. Out-of-Order Blocks - -```cpp -void BlockDownloadCoordinator::block_received( - hash_digest const& hash, - uint32_t height, - block_ptr block -) { - std::lock_guard lock(mutex_); - - // Remove from in-flight - in_flight_.erase(height); - - if (height == next_height_to_validate_) { - // Perfect - validate immediately - validated_blocks_.try_send({}, std::move(block)); - ++next_height_to_validate_; - - // Check if we can validate more from pending - while (auto it = pending_blocks_.find(next_height_to_validate_); - it != pending_blocks_.end()) { - validated_blocks_.try_send({}, std::move(it->second)); - pending_blocks_.erase(it); - ++next_height_to_validate_; - } - } else { - // Out of order - buffer it - pending_blocks_[height] = std::move(block); - } -} -``` - -### Multi-Peer Orchestration - -```cpp -::asio::awaitable parallel_block_sync( - blockchain::block_chain& chain, - p2p_node& network, - uint32_t start_height, - uint32_t target_height -) { - BlockDownloadCoordinator coordinator(start_height, target_height); - - // Get all connected peers - auto peers = co_await network.peers().all(); - if (peers.empty()) { - co_return sync_result{error::no_peers}; - } - - // Create task group for all download coroutines - task_group download_tasks(network.thread_pool().get_executor()); - - // Spawn download loop for each peer - for (auto& peer : peers) { - download_tasks.spawn([&peer, &coordinator]() -> awaitable { - co_await peer_download_loop(peer, coordinator); - }); - } - - // Spawn validation pipeline - download_tasks.spawn([&coordinator, &chain]() -> awaitable { - co_await validation_pipeline(coordinator, chain); - }); - - // Spawn timeout checker - download_tasks.spawn([&coordinator]() -> awaitable { - while (!coordinator.complete()) { - co_await async_sleep(1s); - coordinator.check_timeouts(); - } - }); - - // Wait for all to complete - co_await download_tasks.join(); - - co_return sync_result{error::success, target_height - start_height}; -} -``` - -### Performance Expectations - -| Peers | Blocks/peer | Total In-Flight | Theoretical Speedup | -|-------|-------------|-----------------|---------------------| -| 1 | 16 | 16 | 16x | -| 4 | 16 | 64 | 64x | -| 8 | 16 | 128 | 128x | - -With 100ms latency and 16 blocks in-flight per peer: -- Single peer: 16 blocks / 100ms = 160 blocks/sec -- 8 peers: 128 blocks / 100ms = 1280 blocks/sec - -Actual throughput limited by: -- Bandwidth (block size × blocks/sec) -- Validation speed (CPU-bound) -- Disk I/O - -### Implementation Plan - -1. **Phase 1: BlockDownloadCoordinator class** - - Block assignment logic - - In-flight tracking - - Out-of-order buffering - -2. **Phase 2: Peer download coroutines** - - Batch getdata sending - - Block receiving with timeout - - Integration with coordinator - -3. **Phase 3: Validation pipeline** - - Ordered block processing - - Chain integration - -4. **Phase 4: Adaptive optimizations** - - Peer speed tracking - - Dynamic block assignment - - Slow peer detection - -### File Structure - -``` -src/node/ -├── block_download_coordinator.hpp -├── block_download_coordinator.cpp -├── parallel_sync.hpp -├── parallel_sync.cpp -└── sync_session.cpp (modified to use coordinator) -``` - -### Open Questions - -1. **Should we download from peers we're not fully connected to?** - - BCHN requires handshake complete before requesting blocks - -2. **How to handle forks/reorgs during download?** - - Need to validate headers first, then download blocks for winning chain - -3. **Memory limits for out-of-order buffer?** - - With 1024 window and avg 1MB blocks, could need 1GB buffer - - Consider disk-based buffering for large syncs - -4. **Prioritize recent blocks?** - - During IBD, oldest blocks first - - After IBD, newest blocks (for tip) should have priority - ---- - -## Implementation Status - -### Completed -- [x] `block_download_coordinator` class with parallel download management -- [x] `parallel_sync` orchestration with task_group (nursery pattern) -- [x] Integration with `sync_session` (automatic when p2p_node available) -- [x] Peer download loops with claim/receive pattern -- [x] Validation pipeline (in-order block validation) -- [x] Timeout checker for stalled downloads -- [x] Out-of-order buffering with flush to validation -- [x] Uses `boost::unordered_flat_map` for performance - -### Pending Optimizations - -1. **Batch getdata** (High Priority) - - Current: Each peer sends getdata one block at a time, waits for response - - Optimal: Send batch getdata (16 blocks), receive blocks via message handler - - Requires: New `receive_block_with_timeout()` function in `protocols_coro.hpp` - - Impact: Would reduce round-trip latency by ~16x per peer - -2. **Expose configuration in settings** (Medium Priority) - - Currently: `parallel_download_config` has hardcoded values - - TODO: Add to `node::settings` for user configuration - - Parameters: `max_blocks_per_peer`, `global_window`, `stall_timeout` - -3. **Dynamic memory limits** (Medium Priority) - - Issue: With window=1024 and ~1MB avg blocks, could use ~1GB in worst case - - TODO: Calculate `global_window` based on available system memory - - Consider: Disk-based buffering for very large syncs - -4. **Refactor coordinator to eliminate mutex** (Low Priority) - - Current: Uses `std::mutex` for thread-safe state access - - Alternatives to explore: - - Strand-based serialization (make `claim_blocks` awaitable) - - Actor model with command channel - - Note: Current mutex is acceptable due to low contention (~128 ops/sec) - -5. **Adaptive peer assignment** (Future Enhancement) - - Track peer download speeds - - Assign more blocks to faster peers - - Automatically deprioritize slow peers - -6. **Penalize slow peers** (Future Enhancement) - - If a peer consistently times out, reduce their block allocation - - Consider temporary banning for very slow peers - ---- - -## TODO: Parallel Validation Discussion - -### Current State: Sequential Validation - -Currently, validation happens sequentially: block N must be fully validated before block N+1. - -``` -Download: [====1====] [====2====] [====3====] [====4====] (parallel) -Validation: [====1====][====2====][====3====][====4====] (sequential) -``` - -### What CAN be parallelized? - -1. **Syntax/Format Validation** - - Block header format - - Transaction format - - Merkle root calculation - - Size limits - - These are independent per block - -2. **Script Validation (Signature Checks)** - - ECDSA/Schnorr signature verification is CPU-intensive - - Scripts within a block can be validated in parallel - - Scripts across blocks can potentially be validated in parallel (with caveats) - -3. **PoW Validation** - - Header hash < target - - Independent per block - -### What MUST be sequential? - -1. **UTXO Set Updates** - - Block N creates outputs that block N+1 might spend - - Must apply in order to maintain consistency - -2. **Contextual Validation** - - Coinbase maturity (100 blocks) - - Median time past - - Difficulty adjustment - - BIP activation heights - -### Proposed Architecture - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Download Phase │ -│ Peer1: [blk 100-115] Peer2: [blk 116-131] Peer3: [...] │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Pre-Validation (Parallel) │ -│ - Syntax checks │ -│ - Merkle root │ -│ - PoW validation │ -│ - Script validation (signatures) │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Contextual Validation (Sequential) │ -│ - UTXO lookups and updates │ -│ - Coinbase maturity │ -│ - Median time past │ -│ - Connect to chain │ -└─────────────────────────────────────────────────────────────┘ -``` - -### Questions to Discuss - -1. **Script validation across blocks**: - - Can we validate scripts for block N+1 while block N is being connected? - - Need to handle the case where N+1 spends an output created in N - -2. **Batch signature verification**: - - Schnorr signatures can be batch-verified (faster than individual) - - How to accumulate signatures across blocks? - -3. **UTXO cache strategy**: - - Pre-fetch UTXOs for upcoming blocks? - - Speculative execution with rollback? - -4. **Thread pool sizing**: - - How many threads for script validation? - - Separate pools for download vs validation? - -5. **Assumevalid optimization**: - - Skip script validation for blocks before a known-good hash - - Bitcoin Core uses this for faster IBD - -### References - -- BCHN parallel validation: `src/validation.cpp` -- Bitcoin Core `CheckInputScripts` parallelization -- libsecp256k1 batch verification - ---- - -## Discussion Notes - -(Add notes here as we discuss) diff --git a/hosts.cache b/hosts.cache deleted file mode 100644 index a34d9f6e..00000000 --- a/hosts.cache +++ /dev/null @@ -1,645 +0,0 @@ -23.191.200.9:19798 -65.21.79.59:8333 -101.69.226.138:8333 -35.193.139.211:8333 -94.25.187.239:8333 -75.164.137.188:8433 -83.221.211.116:8333 -143.105.117.74:8330 -70.57.97.122:8333 -212.8.248.197:8333 -31.10.157.171:8333 -45.84.107.200:8333 -116.75.149.83:8333 -109.93.234.55:8339 -116.74.192.64:8333 -185.246.188.149:9663 -45.144.113.253:8333 -109.139.30.102:8336 -158.220.122.39:8333 -85.244.4.208:6335 -82.118.248.205:19798 -185.220.101.24:19798 -116.202.196.52:8333 -143.244.44.175:8333 -104.244.76.237:8333 -23.137.105.248:8333 -157.230.21.198:8333 -185.207.251.50:8333 -91.236.251.138:8333 -209.141.55.26:9333 -69.218.225.129:8333 -102.90.82.109:8333 -167.179.172.173:8333 -154.216.19.10:8334 -34.217.76.29:8333 -1.4.200.149:8333 -136.42.232.7:8333 -176.126.62.152:8333 -176.52.54.126:6335 -194.14.247.36:8333 -54.180.166.112:8333 -72.50.7.43:8333 -185.220.101.181:19798 -75.128.230.115:6335 -108.35.251.240:6335 -219.117.244.105:8333 -114.216.223.123:8333 -2.94.60.118:8333 -187.87.106.4:9333 -193.32.249.217:65001 -1.156.22.158:64454 -85.249.29.39:6335 -118.166.149.5:8333 -84.66.121.155:8333 -149.19.165.195:8333 -212.171.102.227:8333 -185.209.199.95:65001 -198.98.50.112:9333 -54.65.62.127:8333 -96.21.47.54:9333 -23.234.119.118:8333 -193.189.100.206:8333 -107.172.34.196:8333 -78.46.240.210:8333 -198.102.229.253:8333 -202.53.49.202:8333 -35.79.107.85:47963 -95.217.111.35:11011 -5.188.104.245:8339 -173.216.88.59:14522 -212.241.24.147:8333 -183.4.133.120:8333 -191.204.194.52:8333 -79.40.32.207:8333 -49.13.32.144:8333 -213.55.184.49:8333 -47.128.228.87:8334 -5.255.101.131:8333 -178.165.128.167:30008 -216.24.210.151:8333 -54.251.211.75:8333 -143.105.209.32:8333 -37.120.174.180:8333 -185.220.101.50:19798 -185.246.188.74:10333 -165.227.84.200:8963 -133.167.82.173:8333 -147.81.26.71:8333 -134.101.190.231:8333 -54.178.159.239:8333 -216.8.181.249:8333 -185.129.61.8:8333 -54.250.184.95:8333 -176.52.52.4:6335 -91.141.36.118:8333 -87.78.190.15:8333 -172.56.168.149:19665 -119.111.231.247:8333 -152.37.136.203:8333 -79.195.74.220:8323 -135.181.219.10:8433 -54.219.188.176:49088 -39.190.99.154:8333 -185.40.4.127:8333 -18.197.132.221:8333 -172.56.249.36:8333 -54.39.104.128:8333 -109.213.253.48:8333 -23.129.64.198:8333 -87.249.138.133:8333 -177.140.105.178:8335 -151.68.90.113:8333 -152.53.90.71:8333 -81.183.200.65:8337 -4.189.92.202:8333 -95.216.119.109:38333 -45.143.200.32:8333 -203.12.0.126:8333 -150.221.202.248:8333 -128.73.93.121:8333 -173.249.205.122:8334 -84.153.21.72:8335 -46.114.203.255:8333 -144.76.92.36:28333 -185.31.136.173:8333 -81.183.141.187:8333 -8.217.33.31:8333 -111.251.101.180:8333 -81.154.39.95:8333 -129.224.201.176:8333 -78.47.121.92:202 -81.22.58.61:8333 -2.248.89.180:8333 -172.56.11.31:8333 -178.2.151.43:29333 -136.243.147.220:9002 -106.157.175.170:8333 -31.25.241.224:8339 -182.0.236.85:8333 -61.230.95.209:8333 -222.219.107.46:8333 -27.56.141.31:8333 -93.197.37.62:8323 -144.6.96.5:8333 -79.24.244.4:8333 -115.69.29.15:6335 -185.220.101.36:10333 -185.40.4.143:8333 -95.222.185.37:8323 -91.202.26.23:8362 -123.114.100.23:2101 -203.210.222.199:8333 -164.92.120.45:8339 -147.93.156.254:8333 -144.172.118.73:8334 -66.23.234.238:8334 -185.241.208.82:19798 -160.19.35.103:8333 -185.181.60.205:19798 -172.111.156.147:8333 -85.16.0.35:8333 -64.176.47.71:8333 -156.155.10.161:7333 -64.20.53.98:8335 -23.129.64.144:8333 -45.141.215.133:19798 -81.183.139.101:9333 -178.5.111.105:28333 -144.126.141.74:8333 -23.129.64.135:8334 -185.220.101.52:8333 -146.103.43.17:7333 -223.165.102.145:8333 -94.142.241.194:19798 -49.205.106.2:8333 -185.233.100.23:19798 -95.168.105.17:8333 -175.0.57.75:8333 -185.220.101.138:8333 -54.36.209.253:8334 -208.88.16.4:8333 -188.252.166.114:8321 -71.36.122.7:8433 -79.195.69.55:8323 -185.233.93.90:8333 -92.40.170.213:8333 -73.136.36.125:8333 -201.203.117.131:8333 -149.50.218.2:8333 -107.159.8.144:8333 -138.255.59.207:8333 -46.38.238.151:12000 -129.222.192.205:8333 -50.255.99.93:7870 -105.108.148.122:19798 -34.12.224.117:31109 -144.172.118.4:19798 -37.192.75.27:8333 -223.204.71.13:8333 -18.167.190.106:48235 -23.129.64.149:19798 -64.31.58.10:8333 -213.244.206.128:6335 -217.138.219.184:8334 -213.55.185.202:8333 -185.120.89.98:8333 -209.127.122.140:19798 -36.234.205.244:8333 -15.204.52.161:8333 -221.216.137.25:8433 -46.22.5.151:8333 -45.119.84.253:8333 -66.115.146.165:8333 -191.96.150.146:8333 -205.185.113.8:8333 -8.219.86.245:8333 -35.214.103.89:8333 -188.245.217.12:8333 -23.234.71.20:8333 -185.247.194.11:8333 -79.249.188.66:8334 -104.244.79.50:8333 -213.55.184.221:8333 -34.201.132.121:18333 -206.83.114.186:8333 -121.9.181.203:8333 -98.46.105.159:6335 -107.174.71.36:8333 -37.222.245.79:8333 -84.216.194.47:8333 -204.8.96.87:19798 -185.129.62.62:9663 -114.16.18.46:8333 -35.197.99.186:31553 -45.12.111.14:8333 -142.162.9.64:8336 -79.191.99.133:38333 -23.129.64.148:19798 -93.219.208.140:8333 -104.28.228.84:19798 -91.64.72.85:8334 -185.253.183.177:8333 -149.233.239.233:8333 -209.141.34.15:8333 -171.250.121.34:8333 -176.65.134.4:19798 -98.97.39.109:8993 -32.218.131.61:8333 -144.202.5.150:7870 -34.84.123.7:8333 -172.59.185.203:8333 -98.97.27.110:8332 -202.184.104.12:8333 -210.211.61.46:8333 -185.220.101.145:8334 -136.23.10.75:8333 -223.204.216.12:8333 -182.171.102.226:8333 -185.220.101.101:8334 -94.114.117.150:9333 -83.39.163.77:8333 -97.120.0.147:8433 -188.252.166.68:8321 -213.239.204.59:8333 -86.110.236.37:6335 -94.26.249.13:8333 -178.162.138.104:8333 -176.52.57.22:6335 -143.105.151.73:8333 -116.202.241.54:13011 -174.91.231.74:8333 -3.147.82.109:61132 -135.129.113.35:8333 -23.249.26.172:8333 -45.90.185.108:8333 -5.78.24.87:8333 -201.203.117.12:8333 -3.238.219.148:8333 -114.10.117.217:8333 -159.100.240.67:8333 -57.129.84.149:8313 -93.219.223.194:8333 -81.154.39.56:8333 -20.89.134.133:8333 -185.213.154.83:8334 -85.194.204.85:8333 -23.191.200.11:19798 -149.224.0.102:8333 -104.182.218.53:8333 -194.233.174.56:8334 -13.212.246.16:8333 -45.234.213.59:6335 -116.74.199.154:8333 -86.98.180.214:8333 -185.220.101.175:8333 -89.244.90.227:9334 -146.0.75.226:1091 -85.93.218.204:19798 -98.97.26.163:8330 -156.146.51.80:10333 -185.220.101.140:9663 -37.19.198.37:8333 -154.251.104.203:9333 -107.172.143.67:8333 -194.99.104.35:8333 -57.129.84.149:8302 -198.252.125.136:8336 -123.181.162.53:6335 -78.51.70.154:8333 -45.86.200.138:8333 -185.225.232.34:8330 -105.109.136.241:19798 -152.58.60.125:8333 -36.234.219.216:8333 -109.123.55.242:8333 -24.52.248.184:28333 -213.91.128.133:8333 -35.189.84.195:8333 -43.225.189.109:8333 -193.26.115.140:9663 -194.26.192.161:8334 -104.224.120.212:8333 -185.220.101.162:8531 -38.242.254.131:19798 -94.49.30.83:8333 -37.138.165.59:8333 -185.250.38.13:8333 -181.214.165.28:8336 -98.97.37.76:8993 -86.151.48.209:8333 -193.116.225.53:8333 -93.197.40.172:8323 -34.245.64.155:5001 -142.171.106.238:8333 -45.94.208.25:8333 -207.246.85.175:7870 -23.94.220.130:8385 -13.115.38.57:8333 -77.48.28.204:19798 -79.117.129.96:8333 -146.70.117.212:19798 -209.141.55.26:19798 -149.22.108.171:8333 -162.19.7.11:8333 -92.40.219.109:8335 -116.74.195.151:8333 -72.50.4.54:8333 -98.167.206.49:8333 -114.243.97.86:8333 -51.81.184.86:37970 -178.127.27.238:8333 -216.174.70.77:8333 -92.60.40.205:19798 -57.129.18.162:8333 -35.80.222.198:8333 -46.114.92.181:8333 -5.9.56.139:8331 -90.151.86.27:8333 -64.31.58.34:8333 -176.52.57.80:6335 -176.65.149.195:8333 -217.182.198.163:8333 -173.249.58.36:8333 -188.165.37.58:8335 -37.60.231.59:19798 -37.60.229.178:8333 -129.213.76.88:8336 -74.80.182.70:8333 -103.91.65.44:19798 -70.51.240.228:8333 -18.182.192.156:8333 -134.122.93.73:8335 -75.164.145.241:8433 -168.119.162.233:8333 -142.132.136.223:8353 -134.209.237.2:8444 -46.114.244.154:8333 -182.8.226.243:8333 -185.220.101.14:8333 -208.115.211.114:8333 -129.222.194.7:8333 -54.219.188.176:48976 -18.201.212.198:5001 -67.43.230.26:8333 -185.138.88.25:8333 -129.222.195.123:8333 -80.94.92.92:8334 -120.244.194.109:8333 -86.102.40.50:8333 -174.127.145.82:8333 -188.252.166.192:8321 -209.141.40.68:8335 -45.170.114.167:6335 -185.220.101.57:19798 -77.174.124.44:8333 -185.220.101.16:19798 -45.84.107.172:8531 -203.55.81.1:19798 -104.167.242.118:8334 -172.93.221.151:8333 -85.190.254.126:8333 -134.101.220.101:8333 -94.25.168.142:8333 -34.139.57.123:8333 -14.203.85.225:8333 -64.219.160.116:6335 -207.225.131.170:6950 -89.157.2.223:8333 -58.7.215.137:10333 -199.199.199.32:8633 -88.99.225.141:8333 -95.217.246.229:8333 -115.220.182.102:8333 -149.40.62.55:10333 -54.195.221.110:8333 -185.197.250.105:8333 -116.74.192.123:8333 -156.229.232.115:9663 -79.25.225.65:8333 -185.220.101.176:9333 -118.166.147.91:8333 -83.217.13.198:8336 -46.114.169.110:8333 -222.129.37.84:3101 -23.191.200.9:8333 -209.198.131.41:8333 -194.15.112.133:8335 -54.219.188.176:17262 -116.74.184.254:8333 -116.74.196.145:8333 -47.156.34.225:6335 -36.234.231.145:8333 -146.70.211.19:8333 -194.54.144.97:8333 -45.83.220.216:8333 -85.208.139.110:19798 -167.114.119.46:8333 -114.223.221.47:8733 -82.77.102.212:10863 -47.128.78.31:8333 -159.196.169.50:18333 -5.255.117.56:10333 -34.124.164.210:8333 -20.82.44.15:7333 -190.56.195.67:8333 -162.247.74.27:9333 -5.255.99.147:19798 -185.238.121.58:8333 -64.130.45.91:8333 -178.165.186.211:30008 -79.141.163.112:8333 -138.84.36.210:8333 -111.248.218.228:8333 -149.224.82.172:8333 -81.222.190.97:6335 -185.254.196.141:19798 -129.222.196.90:8333 -178.122.206.166:8333 -206.83.112.191:8333 -5.2.79.190:8333 -111.199.186.107:3101 -176.83.49.14:8333 -162.247.72.192:10333 -93.197.47.15:8323 -120.40.199.117:8333 -83.22.193.219:8333 -193.26.115.140:8333 -114.24.138.118:8333 -109.202.110.57:8333 -58.84.61.31:8333 -174.89.243.132:8333 -116.74.175.129:8333 -5.35.69.163:8333 -95.71.167.224:8333 -37.45.160.173:8333 -185.220.101.82:19798 -121.43.153.48:8333 -77.183.178.1:8333 -195.176.3.24:19798 -24.1.77.227:8333 -46.114.242.176:8333 -51.91.80.241:8333 -185.220.101.48:531 -122.172.87.47:8333 -194.163.156.221:8333 -73.84.169.252:8333 -46.114.170.184:8333 -103.146.203.11:19798 -73.3.203.128:8333 -83.217.13.202:8336 -167.99.60.46:8332 -62.171.137.169:8333 -185.129.62.64:8334 -194.71.227.135:8334 -146.70.194.25:8333 -172.245.178.167:8333 -111.251.68.16:8333 -98.159.36.152:8333 -65.68.45.165:6335 -173.234.17.198:8333 -23.137.248.100:19798 -212.216.140.141:8333 -89.147.108.90:19798 -91.249.95.39:8333 -151.54.241.102:8333 -206.71.158.65:19798 -39.71.151.134:8333 -46.114.219.106:8333 -109.252.70.74:8333 -81.25.170.30:8333 -176.52.57.239:6335 -49.182.78.110:8333 -98.46.105.106:6335 -211.30.131.137:8333 -23.22.205.67:18333 -46.147.150.160:8333 -195.154.167.36:8333 -49.43.43.7:8333 -111.250.63.15:8333 -60.236.93.160:8333 -157.100.198.164:6335 -45.13.225.69:9663 -54.158.91.224:8333 -31.150.127.253:8333 -45.12.52.30:8333 -185.107.57.66:19798 -171.25.193.38:8333 -95.179.139.47:8333 -213.21.32.220:8333 -104.199.92.57:46964 -188.165.77.110:9333 -98.97.41.80:8993 -46.114.88.14:8333 -157.50.174.91:8333 -45.83.104.137:10333 -89.164.36.23:8333 -72.50.4.55:8333 -39.78.148.20:8333 -185.42.170.203:19798 -93.181.204.102:8333 -104.244.79.44:19798 -73.22.179.110:8333 -47.245.28.85:8333 -77.119.211.215:8333 -95.52.114.73:18333 -195.26.231.109:8373 -88.130.80.203:6335 -52.30.206.240:8333 -81.89.56.2:52964 -107.161.89.155:8385 -185.220.101.56:10333 -119.126.168.62:8333 -95.217.73.169:8333 -188.214.104.21:8334 -5.249.38.235:8333 -125.119.157.238:8333 -162.55.230.100:8333 -194.36.145.176:8333 -39.71.151.173:8333 -35.187.240.10:8333 -60.48.93.156:8333 -80.3.166.236:8333 -49.76.141.14:8733 -185.220.101.56:9333 -77.223.102.9:8333 -91.215.89.105:8333 -82.77.81.56:8333 -81.91.189.241:8133 -23.129.64.164:7333 -193.26.115.140:19798 -169.155.251.12:8333 -103.230.184.159:8333 -91.23.153.193:8323 -149.56.16.133:8333 -18.142.36.118:8333 -5.189.186.199:8333 -149.22.108.29:8333 -148.113.16.157:8333 -143.244.42.67:7333 -35.243.80.95:8333 -64.190.76.12:19798 -182.165.86.69:8333 -62.3.53.10:8435 -87.17.89.186:8334 -88.80.26.3:19798 -155.133.22.65:8333 -190.47.66.182:8333 -46.114.246.178:8333 -92.234.19.156:28333 -86.54.28.49:19798 -169.150.218.83:10333 -191.54.39.66:8333 -185.130.47.58:9333 -195.47.238.91:8333 -51.91.18.151:19798 -117.84.219.95:8733 -152.57.43.122:8333 -61.230.72.44:8333 -35.200.60.45:8333 -13.57.191.34:8333 -149.22.108.119:8333 -197.99.36.142:8333 -61.223.221.81:8333 -23.137.254.137:8334 -84.247.187.110:8333 -84.86.187.232:8333 -23.184.48.127:10333 -75.164.137.206:8433 -156.248.8.96:8333 -203.9.210.97:19798 -34.243.233.30:5001 -45.141.215.111:8334 -85.249.25.190:8333 -176.247.45.235:8333 -193.81.233.121:39388 -174.219.126.155:8333 -217.142.22.140:8333 -176.65.149.148:19798 -101.128.96.175:6335 -31.220.78.89:8333 -52.38.59.165:8333 -117.241.248.15:8333 -23.191.200.13:8334 -185.213.80.55:8333 -3.252.227.104:50072 -185.193.88.3:8338 -95.158.207.161:45833 -46.114.212.209:8333 -89.247.166.72:8333 -35.197.99.186:31341 -185.220.101.159:10333 -138.199.21.242:8333 -188.252.164.42:8321 -79.137.68.69:8333 -171.25.193.35:19798 -43.198.67.141:8333 -18.139.1.192:8333 -47.156.147.150:8333 -85.249.31.120:8333 -213.168.89.164:8333 -93.85.162.78:8333 -114.223.15.143:8733 -201.206.180.3:8333 -23.129.64.217:9333 -34.172.151.203:8333 diff --git a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp index 1316e017..c94932c1 100644 --- a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp +++ b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp @@ -76,9 +76,8 @@ struct KB_API block_chain { // ORGANIZERS (Core blockchain operations) // ========================================================================= - /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable organize(block_const_ptr block, bool headers_pre_validated = false); + ::asio::awaitable organize(block_const_ptr block); [[nodiscard]] ::asio::awaitable organize(transaction_const_ptr tx); @@ -187,7 +186,6 @@ struct KB_API block_chain { [[nodiscard]] std::expected, database::result_code> get_transaction_position( hash_digest const& hash, bool require_confirmed) const; - [[nodiscard]] bool header_exists(hash_digest const& block_hash) const; [[nodiscard]] bool block_exists(hash_digest const& block_hash) const; // ========================================================================= diff --git a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp index 369f3bd9..cb0e78ae 100644 --- a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp @@ -50,9 +50,8 @@ struct KB_API block_organizer { bool stop(); /// Organize a block - coroutine version - /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable organize(block_const_ptr block, bool headers_pre_validated = false); + ::asio::awaitable organize(block_const_ptr block); [[nodiscard]] block_broadcaster::channel_ptr subscribe(); diff --git a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp index 34105a96..adfbb8b7 100644 --- a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp @@ -106,11 +106,6 @@ struct KB_API header_organizer { [[nodiscard]] hash_digest const& header_tip_hash() const { return tip_hash_; } - /// Get the timestamp of the header tip. - /// Used for BCHN-style progress calculation. - [[nodiscard]] - uint32_t tip_timestamp() const; - /// Get the number of headers in the index. [[nodiscard]] size_t size() const { return index_.size(); } @@ -124,13 +119,10 @@ struct KB_API header_organizer { bool stopped() const { return stopped_; } private: - // Validate a single header with full chain-state validation - // Includes: PoW check, difficulty, checkpoint, version, MTP + // Validate a single header against expected previous [[nodiscard]] - code validate_full(domain::chain::header const& header, - hash_digest const& hash, - int32_t height, - header_index::index_t parent_idx) const; + code validate(domain::chain::header const& header, int32_t height, + hash_digest const& previous) const; // Members header_index& index_; diff --git a/src/blockchain/include/kth/blockchain/settings.hpp b/src/blockchain/include/kth/blockchain/settings.hpp index 79d4cd5b..8cff1e78 100644 --- a/src/blockchain/include/kth/blockchain/settings.hpp +++ b/src/blockchain/include/kth/blockchain/settings.hpp @@ -32,8 +32,6 @@ struct KB_API settings { uint32_t notify_limit_hours = 24; uint32_t reorganization_limit = 256; infrastructure::config::checkpoint::list checkpoints; - infrastructure::config::checkpoint::list checkpoints_sorted; // Pre-sorted by height - size_t max_checkpoint_height = 0; // Pre-computed max bool fix_checkpoints = true; bool allow_collisions = true; bool easy_blocks = false; diff --git a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp index c8ad1b15..800b6fe6 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp @@ -41,32 +41,15 @@ struct KB_API validate_block { void start(); void stop(); - /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable check(block_const_ptr block, bool headers_pre_validated = false) const; + ::asio::awaitable check(block_const_ptr block) const; - /// @param headers_pre_validated If true, use accept_body() to skip header validation [[nodiscard]] - ::asio::awaitable accept(branch::const_ptr branch, bool headers_pre_validated = false) const; + ::asio::awaitable accept(branch::const_ptr branch) const; [[nodiscard]] ::asio::awaitable connect(branch::const_ptr branch) const; - // ========================================================================= - // Static validation functions (pure, no side effects) - // These replace the accept/connect methods that were in block_basis. - // ========================================================================= - - /// Validate block body against chain state (skip header validation). - /// Validates: block size, transaction ordering, coinbase, finality. - /// @param block The block to validate. - /// @param state The chain state for context. - /// @return error::success or validation error. - [[nodiscard]] - static code accept_block_body( - domain::chain::block const& block, - domain::chain::chain_state const& state); - protected: [[nodiscard]] bool stopped() const { diff --git a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp index eebf11b5..f7337579 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp @@ -7,10 +7,8 @@ #include #include -#include #include -#include #include #include @@ -37,10 +35,6 @@ struct KB_API validate_header { /// @param[in] network The network type (mainnet, testnet, etc). validate_header(settings const& settings, domain::config::network network); - /// Access the settings. - [[nodiscard]] - settings const& chain_settings() const { return settings_; } - /// Context-free validation (PoW + timestamp). /// Validates: /// - Proof of work is valid for the claimed difficulty (bits) @@ -74,67 +68,6 @@ struct KB_API validate_header { code validate(domain::chain::header const& header, size_t height, hash_digest const& previous) const; - // ========================================================================= - // Full validation with header_index (for headers-first sync) - // ========================================================================= - - /// Full accept validation using header_index to build chain_state. - /// This performs complete header validation including: - /// - Chain continuity (previous block hash) - /// - Checkpoint validation - /// - Difficulty check (work_required) - /// - Version check (minimum_version) - /// - Median time past check - /// - /// @param[in] header The header to validate. - /// @param[in] hash The header's hash. - /// @param[in] height The height of this header. - /// @param[in] parent_idx Index of parent header in the index. - /// @param[in] index The header index containing historical data. - /// @return error::success or the validation error. - [[nodiscard]] - code accept_full(domain::chain::header const& header, - hash_digest const& hash, - size_t height, - header_index::index_t parent_idx, - header_index const& index) const; - - /// Build chain_state::data from header_index for a given height. - /// This collects the historical bits, versions, and timestamps needed - /// to construct a chain_state for validation. - /// - /// @param[in] height The target height. - /// @param[in] header The header at target height. - /// @param[in] hash The header's hash. - /// @param[in] parent_idx Index of parent header in the index. - /// @param[in] index The header index containing historical data. - /// @return chain_state::data populated from the index, or error code on failure. - [[nodiscard]] - std::expected build_chain_state_data( - size_t height, - domain::chain::header const& header, - hash_digest const& hash, - header_index::index_t parent_idx, - header_index const& index) const; - - // ========================================================================= - // Static validation functions (pure, no side effects) - // These can be called without a validate_header instance when chain_state - // is already available. - // ========================================================================= - - /// Validate header against chain state. - /// Validates: difficulty, checkpoint, version, MTP. - /// @param header The header to validate. - /// @param hash The header hash. - /// @param state The chain state for context. - /// @return error::success or validation error. - [[nodiscard]] - static code accept_header( - domain::chain::header const& header, - hash_digest const& hash, - domain::chain::chain_state const& state); - /// Check if a height is under checkpoint protection. /// Headers under checkpoint can skip some validation. [[nodiscard]] @@ -157,24 +90,8 @@ struct KB_API validate_header { [[nodiscard]] size_t last_checkpoint_height() const; - /// Collect historical data (bits, versions, timestamps) from header_index. - /// Single traversal for efficiency. - [[nodiscard]] - std::expected collect_historical_data( - domain::chain::chain_state::map const& map, - header_index::index_t parent_idx, - header_index const& index) const; - -#if defined(KTH_CURRENCY_BCH) - /// Get the ASERT anchor block info for the network. - [[nodiscard]] - domain::chain::chain_state::assert_anchor_block_info_t get_asert_anchor_block() const; -#endif - // Configuration - settings const& settings_; checkpoint_list const checkpoints_; - uint32_t const configured_forks_; domain::config::network const network_; bool const retarget_; // Whether PoW retargeting is enabled (mainnet=true) }; diff --git a/src/blockchain/src/interface/block_chain.cpp b/src/blockchain/src/interface/block_chain.cpp index 08335974..9385d6e4 100644 --- a/src/blockchain/src/interface/block_chain.cpp +++ b/src/blockchain/src/interface/block_chain.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -143,69 +142,16 @@ bool block_chain::start() { return false; } - // Load all headers from database into header_index - // This allows resuming sync from where we left off - auto const heights = get_last_heights(); - if ( ! heights) { - spdlog::error("[blockchain] Failed to get last heights from database."); - return false; - } - - auto const [header_height, block_height] = *heights; - spdlog::info("[blockchain] Database state: header_height={}, block_height={}", header_height, block_height); - - if (header_height == 0) { - // Only genesis in DB - just add genesis to index - auto const genesis = get_header(0); - if (genesis) { - auto const hash = genesis->hash(); - auto const [inserted, idx, capacity_warning] = header_index_.add(hash, *genesis); - if ( ! inserted) { - spdlog::error("[blockchain] Failed to initialize header index with genesis block."); - return false; - } - spdlog::info("[blockchain] Header index initialized with genesis: {}", encode_hash(hash)); + // Initialize header_index with genesis block + auto const genesis = get_header(0); + if (genesis) { + auto const hash = genesis->hash(); + auto const [inserted, index, capacity_warning] = header_index_.add(hash, *genesis); + if ( ! inserted) { + spdlog::error("[blockchain] Failed to initialize header index with genesis block."); + return false; } - } else { - // Load all headers from DB into header_index - spdlog::info("[blockchain] Loading {} headers from database into header_index...", header_height + 1); - - auto const load_start = std::chrono::steady_clock::now(); - - // Load in batches to avoid memory spikes - constexpr size_t batch_size = 10000; - size_t loaded = 0; - - for (size_t from = 0; from <= header_height; from += batch_size) { - auto const to = std::min(from + batch_size - 1, header_height); - auto const headers_result = get_headers(from, to); - - if ( ! headers_result) { - spdlog::error("[blockchain] Failed to load headers from {} to {}", from, to); - return false; - } - - size_t height = from; - for (auto const& header : *headers_result) { - auto const hash = header.hash(); - auto const [inserted, idx, capacity_warning] = header_index_.add(hash, header); - if ( ! inserted && height > 0) { - // Genesis might already be added, ignore that case - spdlog::warn("[blockchain] Failed to add header at height {} to index", height); - } - ++height; - ++loaded; - } - - // Log progress every 100k headers - if (loaded % 100000 < batch_size && loaded > 0) { - spdlog::info("[blockchain] Loaded {}/{} headers into index...", loaded, header_height + 1); - } - } - - auto const elapsed = std::chrono::steady_clock::now() - load_start; - auto const elapsed_ms = std::chrono::duration_cast(elapsed).count(); - spdlog::info("[blockchain] Loaded {} headers into header_index in {}ms", loaded, elapsed_ms); + spdlog::info("[blockchain] Header index initialized with genesis: {}", encode_hash(hash)); } return true; @@ -236,8 +182,8 @@ bool block_chain::stopped() const { // ORGANIZERS (Core blockchain operations) // ============================================================================= -::asio::awaitable block_chain::organize(block_const_ptr block, bool headers_pre_validated) { - co_return co_await block_organizer_.organize(block, headers_pre_validated); +::asio::awaitable block_chain::organize(block_const_ptr block) { + co_return co_await block_organizer_.organize(block); } ::asio::awaitable block_chain::organize(transaction_const_ptr tx) { @@ -459,7 +405,7 @@ std::expected, database::result_code> block_chain::get return std::unexpected(result.error()); } auto const& [header_height, block_height] = *result; - return std::pair{size_t(header_height), size_t(block_height)}; + return std::pair{static_cast(header_height), static_cast(block_height)}; } std::expected block_chain::get_header(size_t height) const { @@ -514,29 +460,8 @@ std::expected block_chain::get_block_hash(si return result->hash(); } -bool block_chain::header_exists(hash_digest const& block_hash) const { - return database_.internal_db().get_header(block_hash).has_value(); -} - bool block_chain::block_exists(hash_digest const& block_hash) const { - // Check if full block exists (not just header) - // With headers-first sync, headers may exist without full blocks - auto const header_result = database_.internal_db().get_header(block_hash); - if (!header_result) { - return false; // Header doesn't exist, so block doesn't exist - } - - // Header exists - check if we have the full block - auto const heights = database_.internal_db().get_last_heights(); - if (!heights) { - return false; - } - - auto const [header_height, block_height] = *heights; - auto const this_block_height = header_result->second; - - // Block exists only if its height <= block_height - return this_block_height <= block_height; + return database_.internal_db().get_header(block_hash).has_value(); } std::expected block_chain::get_branch_work(uint256_t const& maximum, size_t from_height) const { @@ -544,9 +469,7 @@ std::expected block_chain::get_branch_work(uin if ( ! heights) { return std::unexpected(heights.error()); } - // Use block_height (not header_height) for work comparison - // With headers-first sync, we may have headers without full blocks - auto const top = heights->second; // block_height + auto const top = heights->first; // header_height uint256_t out_work = 0; for (uint32_t height = from_height; height <= top && out_work < maximum; ++height) { diff --git a/src/blockchain/src/pools/block_organizer.cpp b/src/blockchain/src/pools/block_organizer.cpp index a7d01b7a..cd418fcf 100644 --- a/src/blockchain/src/pools/block_organizer.cpp +++ b/src/blockchain/src/pools/block_organizer.cpp @@ -83,7 +83,7 @@ bool block_organizer::stop() { // Organize sequence. //----------------------------------------------------------------------------- -::asio::awaitable block_organizer::organize(block_const_ptr block, bool headers_pre_validated) { +::asio::awaitable block_organizer::organize(block_const_ptr block) { // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_high_priority(); //TODO: is it possible to remove this mutex? @@ -101,8 +101,7 @@ ::asio::awaitable block_organizer::organize(block_const_ptr block, bool he } // Checks that are independent of chain state. - // For headers-first sync, skip header validation since headers were already validated. - auto ec = co_await validator_.check(block, headers_pre_validated); + auto ec = co_await validator_.check(block); if (stopped()) { mutex_.unlock_high_priority(); @@ -135,8 +134,7 @@ ::asio::awaitable block_organizer::organize(block_const_ptr block, bool he } // Checks that are dependent on chain state and prevouts. - // For headers-first sync, use accept_body() to skip header validation. - ec = co_await validator_.accept(branch, headers_pre_validated); + ec = co_await validator_.accept(branch); if (stopped()) { mutex_.unlock_high_priority(); diff --git a/src/blockchain/src/pools/header_organizer.cpp b/src/blockchain/src/pools/header_organizer.cpp index af0851fb..a9f05ee6 100644 --- a/src/blockchain/src/pools/header_organizer.cpp +++ b/src/blockchain/src/pools/header_organizer.cpp @@ -82,15 +82,9 @@ header_organize_result header_organizer::add_headers(domain::message::header::li height, encode_hash(tip_hash_)); for (auto const& header : headers) { - // Compute hash first (needed for validation) - KTH_STATS_TIME_START(hash); - auto const hash = header.hash(); - KTH_STATS_TIME_END(global_sync_stats(), hash, hash_time_ns, hash_calls); - - // Validate header with full chain-state validation - // This includes: PoW check, difficulty, checkpoint, version, MTP + // Validate header KTH_STATS_TIME_START(validate); - auto const ec = validate_full(header, hash, height, tip_index_); + auto const ec = validate(header, height, prev_hash); KTH_STATS_TIME_END(global_sync_stats(), validate, validate_time_ns, validate_calls); if (ec) { @@ -100,6 +94,11 @@ header_organize_result header_organizer::add_headers(domain::message::header::li break; } + // Compute hash and add to index + KTH_STATS_TIME_START(hash); + auto const hash = header.hash(); + KTH_STATS_TIME_END(global_sync_stats(), hash, hash_time_ns, hash_calls); + KTH_STATS_TIME_START(index_add); auto const add_result = index_.add(hash, header); KTH_STATS_TIME_END(global_sync_stats(), index_add, index_add_time_ns, index_add_calls); @@ -124,10 +123,10 @@ header_organize_result header_organizer::add_headers(domain::message::header::li } // Log progress every 1000 headers - // if (result.headers_added > 0 && result.headers_added % 1000 == 0) { - // spdlog::debug("[header_organizer] Validated {} headers, height {}...", - // result.headers_added, height - 1); - // } + if (result.headers_added > 0 && result.headers_added % 1000 == 0) { + spdlog::debug("[header_organizer] Validated {} headers, height {}...", + result.headers_added, height - 1); + } } spdlog::debug("[header_organizer] Validation complete: {} headers added, total size {}", @@ -150,33 +149,13 @@ int32_t header_organizer::header_height() const { return index_.get_height(tip_index_); } -uint32_t header_organizer::tip_timestamp() const { - if (tip_index_ == header_index::null_index) { - return 0; - } - return index_.get_timestamp(tip_index_); -} - // ============================================================================= // Validation // ============================================================================= -code header_organizer::validate_full(domain::chain::header const& header, - hash_digest const& hash, - int32_t height, - header_index::index_t parent_idx) const { - // First do context-free check (PoW, timestamp not too far in future) - // Skip PoW check if under checkpoint (trusted headers) - if (!validator_.is_under_checkpoint(size_t(height))) { - auto const ec = validator_.check(header); - if (ec) { - return ec; - } - } - - // Then do full accept validation with chain_state built from header_index - // This validates: difficulty, checkpoint, version, MTP - return validator_.accept_full(header, hash, size_t(height), parent_idx, index_); +code header_organizer::validate(domain::chain::header const& header, int32_t height, + hash_digest const& previous) const { + return validator_.validate(header, static_cast(height), previous); } } // namespace kth::blockchain diff --git a/src/blockchain/src/populate/populate_chain_state.cpp b/src/blockchain/src/populate/populate_chain_state.cpp index 77d14824..eca77ff9 100644 --- a/src/blockchain/src/populate/populate_chain_state.cpp +++ b/src/blockchain/src/populate/populate_chain_state.cpp @@ -36,7 +36,7 @@ populate_chain_state::populate_chain_state(block_chain const& chain, settings co settings_(settings), #endif //KTH_CURRENCY_BCH configured_forks_(settings.enabled_forks()) - , checkpoints_(settings.checkpoints_sorted) + , checkpoints_(infrastructure::config::checkpoint::sort(settings.checkpoints)) , network_(network) , chain_(chain) {} diff --git a/src/blockchain/src/settings.cpp b/src/blockchain/src/settings.cpp index a5dbc056..1d4e5c20 100644 --- a/src/blockchain/src/settings.cpp +++ b/src/blockchain/src/settings.cpp @@ -70,12 +70,6 @@ settings::settings(domain::config::network net) { } checkpoints = domain::config::default_checkpoints(net); - - // Pre-compute sorted list and max height - checkpoints_sorted = infrastructure::config::checkpoint::sort(checkpoints); - if (!checkpoints_sorted.empty()) { - max_checkpoint_height = checkpoints_sorted.back().height(); - } } uint32_t settings::enabled_forks() const { diff --git a/src/blockchain/src/validate/validate_block.cpp b/src/blockchain/src/validate/validate_block.cpp index 253ae417..395cbe62 100644 --- a/src/blockchain/src/validate/validate_block.cpp +++ b/src/blockchain/src/validate/validate_block.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -67,7 +66,7 @@ void validate_block::stop() { //----------------------------------------------------------------------------- // These checks are context free. -::asio::awaitable validate_block::check(block_const_ptr block, bool headers_pre_validated) const { +::asio::awaitable validate_block::check(block_const_ptr block) const { // The block hasn't been checked yet. if (block->transactions().empty()) { co_return error::success; @@ -109,11 +108,6 @@ ::asio::awaitable validate_block::check(block_const_ptr block, bool header } // Run context free checks, sets time internally. - // For headers-first sync, skip header validation (PoW, timestamp) since - // headers were already validated during header sync. - if (headers_pre_validated) { - co_return block->check_body(); - } co_return block->check(); } @@ -136,7 +130,7 @@ code validate_block::check_block_bucket(block_const_ptr block, size_t bucket, si //----------------------------------------------------------------------------- // These checks require chain state, and block state if not under checkpoint. -::asio::awaitable validate_block::accept(branch::const_ptr branch, bool headers_pre_validated) const { +::asio::awaitable validate_block::accept(branch::const_ptr branch) const { auto const block = branch->top(); KTH_ASSERT(block); @@ -161,39 +155,30 @@ ::asio::awaitable validate_block::accept(branch::const_ptr branch, bool he co_return populate_ec; } - auto const& state = *block->validation.state; + auto const height = block->validation.state->height(); // Run contextual block non-tx checks (sets start time). - // For headers-first sync, skip header validation since headers were - // already validated during header sync. - if ( ! headers_pre_validated) { - // Full validation: validate header first - auto const header_ec = validate_header::accept_header(block->header(), block->hash(), state); - if (header_ec) { - co_return header_ec; - } - } + auto const error_code = block->accept(false); - // Validate block body (same for both cases) - auto const body_ec = accept_block_body(*block, state); - if (body_ec) { - co_return body_ec; + if (error_code) { + co_return error_code; } auto const sigops = std::make_shared(0); - + auto const state = block->validation.state; + KTH_ASSERT(state); #if defined(KTH_CURRENCY_BCH) bool const bip141 = false; #else - auto const bip141 = state.is_enabled(domain::machine::rule_fork::bip141_rule); + auto const bip141 = state->is_enabled(domain::machine::rule_fork::bip141_rule); #endif - if (state.is_under_checkpoint()) { + if (state->is_under_checkpoint()) { co_return error::success; } auto const count = block->transactions().size(); - auto const bip16 = state.is_enabled(domain::machine::rule_fork::bip16_rule); + auto const bip16 = state->is_enabled(domain::machine::rule_fork::bip16_rule); auto const buckets = std::min(threads_, count); KTH_ASSERT(buckets != 0); @@ -419,95 +404,4 @@ void validate_block::dump(code const& ec, transaction const& tx, uint32_t input_ prevout.validation.cache.value(), tx_hash, input_index, encode_base16(tx.to_data(true))); } -// ============================================================================= -// Static validation functions (pure, no side effects) -// These replace the accept/connect methods that were in block_basis. -// ============================================================================= - -code validate_block::accept_block_body( - domain::chain::block const& block, - domain::chain::chain_state const& state) { - - auto const& header = block.header(); - auto const block_size = block.serialized_size(); - - auto const bip16 = state.is_enabled(domain::machine::rule_fork::bip16_rule); - auto const bip34 = state.is_enabled(domain::machine::rule_fork::bip34_rule); - auto const bip113 = state.is_enabled(domain::machine::rule_fork::bip113_rule); - auto const bip141 = false; // No segwit - - // Block size validation -#if defined(KTH_CURRENCY_BCH) - if (state.is_lobachevski_enabled()) { - if (block_size > state.dynamic_max_block_size()) { - return error::block_size_limit; - } - } else if (state.is_pythagoras_enabled()) { - if (block_size > static_max_block_size(state.network())) { - return error::block_size_limit; - } - } else { - if (block_size > max_block_size::mainnet_old) { - return error::block_size_limit; - } - } -#else - if (block_size > max_block_size::mainnet_old) { - return error::block_size_limit; - } -#endif - - // Under checkpoint: Only verify merkle root (done in check_body) - if (state.is_under_checkpoint()) { - return error::success; - } - - // Transaction ordering check -#if defined(KTH_CURRENCY_BCH) - if (state.is_euclid_enabled()) { - if ( ! block.is_canonical_ordered()) { - return error::non_canonical_ordered; - } - } else { - if (block.is_forward_reference()) { - return error::forward_reference; - } - } -#else - if (block.is_forward_reference()) { - return error::forward_reference; - } -#endif - - // Coinbase script height check (BIP34) - if (bip34 && !block.is_valid_coinbase_script(state.height())) { - return error::coinbase_height_mismatch; - } - - // Coinbase claim check - if ( ! block.is_valid_coinbase_claim(state.height())) { - return error::coinbase_value_limit; - } - - // Finality check - auto const block_time = bip113 ? state.median_time_past() : header.timestamp(); - if ( ! block.is_final(state.height(), block_time)) { - return error::block_non_final; - } - - // Sigops check (for non-Fermat BCH or BTC/LTC) -#if defined(KTH_CURRENCY_BCH) - if ( ! state.is_fermat_enabled()) { -#endif - size_t const allowed_sigops = get_allowed_sigops(block_size); - if (block.signature_operations(bip16, bip141) > allowed_sigops) { - return error::block_embedded_sigop_limit; - } -#if defined(KTH_CURRENCY_BCH) - } -#endif - - return error::success; -} - } // namespace kth::blockchain diff --git a/src/blockchain/src/validate/validate_header.cpp b/src/blockchain/src/validate/validate_header.cpp index 75ecffb4..2ee02e78 100644 --- a/src/blockchain/src/validate/validate_header.cpp +++ b/src/blockchain/src/validate/validate_header.cpp @@ -5,11 +5,9 @@ #include #include -#include #include -#include #include #include @@ -19,9 +17,7 @@ using namespace kth::domain::chain; using namespace kth::infrastructure::config; validate_header::validate_header(settings const& settings, domain::config::network network) - : settings_(settings) - , checkpoints_(settings.checkpoints_sorted) - , configured_forks_(settings.enabled_forks()) + : checkpoints_(checkpoint::sort(settings.checkpoints)) , network_(network) , retarget_(network != domain::config::network::regtest) {} @@ -129,314 +125,4 @@ size_t validate_header::last_checkpoint_height() const { return checkpoints_.back().height(); } -// ============================================================================= -// Full validation with header_index -// ============================================================================= - -std::expected validate_header::collect_historical_data( - chain_state::map const& map, - header_index::index_t parent_idx, - header_index const& index) const { - - chain_state::data data{}; - - // Resize all containers - data.bits.ordered.resize(map.bits.count); - data.version.ordered.resize(map.version.count); - data.timestamp.ordered.resize(map.timestamp.count); - - // Calculate maximum steps needed - auto const max_count = std::max({map.bits.count, map.version.count, map.timestamp.count}); - - if (max_count == 0) { - return data; - } - - // Single traversal collecting all data types - auto idx = parent_idx; - for (size_t step = 0; step < max_count && idx != header_index::null_index; ++step) { - // Collect bits if still needed (store in reverse order) - if (step < map.bits.count) { - data.bits.ordered[map.bits.count - 1 - step] = index.get_bits(idx); - } - - // Collect versions if still needed - if (step < map.version.count) { - data.version.ordered[map.version.count - 1 - step] = index.get_version(idx); - } - - // Collect timestamps if still needed - if (step < map.timestamp.count) { - data.timestamp.ordered[map.timestamp.count - 1 - step] = index.get_timestamp(idx); - } - - idx = index.get_parent_index(idx); - } - - // Verify we collected enough data - if (idx == header_index::null_index) { - // Check if we collected all required data - auto const parent_height = index.get_height(parent_idx); - if (parent_height + 1 < static_cast(max_count)) { - spdlog::warn("[validate_header] collect_historical_data: insufficient chain depth, " - "need {} but only have {}", max_count, parent_height + 1); - return std::unexpected(error::operation_failed); - } - } - - // Collect retarget timestamp if needed (separate lookup via skip pointers) - if (map.timestamp_retarget != chain_state::map::unrequested) { - auto const retarget_height = static_cast(map.timestamp_retarget); - auto retarget_idx = index.get_ancestor(parent_idx, retarget_height); - - if (retarget_idx == header_index::null_index) { - spdlog::warn("[validate_header] collect_historical_data: could not find retarget ancestor at height {}", - retarget_height); - return std::unexpected(error::operation_failed); - } - -#if defined(KTH_CURRENCY_LTC) - // Litecoin uses (retarget - 1) for some reason - if (retarget_height > 0) { - retarget_idx = index.get_parent_index(retarget_idx); - } -#endif - data.timestamp.retarget = index.get_timestamp(retarget_idx); - } - - return data; -} - -#if defined(KTH_CURRENCY_BCH) -chain_state::assert_anchor_block_info_t validate_header::get_asert_anchor_block() const { - using namespace kth::domain; - - auto const height = network_map(network_ - , mainnet_asert_anchor_block_height - , testnet_asert_anchor_block_height - , size_t(0) - , testnet4_asert_anchor_block_height - , scalenet_asert_anchor_block_height - , chipnet_asert_anchor_block_height - ); - - auto const ancestor_time = network_map(network_ - , mainnet_asert_anchor_block_ancestor_time - , testnet_asert_anchor_block_ancestor_time - , size_t(0) - , testnet4_asert_anchor_block_ancestor_time - , scalenet_asert_anchor_block_ancestor_time - , chipnet_asert_anchor_block_ancestor_time - ); - - uint32_t const bits = network_map(network_ - , mainnet_asert_anchor_block_bits - , testnet_asert_anchor_block_bits - , size_t(0) - , testnet4_asert_anchor_block_bits - , scalenet_asert_anchor_block_bits - , chipnet_asert_anchor_block_bits - ); - - return {height, ancestor_time, bits}; -} -#endif // KTH_CURRENCY_BCH - -std::expected validate_header::build_chain_state_data( - size_t height, - domain::chain::header const& header, - hash_digest const& hash, - header_index::index_t parent_idx, - header_index const& index) const { - - if (height == 0) { - spdlog::warn("[validate_header] build_chain_state_data: height 0 is not valid"); - return std::unexpected(error::operation_failed); - } - - // Get the map that defines what data we need to collect - auto const map = chain_state::get_map(height, checkpoints_, configured_forks_, network_); - - // Collect historical data from header_index (single traversal) - auto result = collect_historical_data(map, parent_idx, index); - if (!result) { - return std::unexpected(result.error()); - } - - auto& data = *result; - - // Set metadata - data.height = height; - data.hash = hash; - - // Set self values from the header being validated - data.bits.self = header.bits(); - data.version.self = header.version(); - data.timestamp.self = header.timestamp(); - - // Handle collision hash (for duplicate tx hash detection) - if (map.allow_collisions_height != chain_state::map::unrequested) { - auto const collision_idx = index.get_ancestor(parent_idx, static_cast(map.allow_collisions_height)); - data.allow_collisions_hash = (collision_idx != header_index::null_index) - ? index.get_hash(collision_idx) - : null_hash; - } else { - data.allow_collisions_hash = null_hash; - } - -#if ! defined(KTH_CURRENCY_BCH) - // BIP9 bit0/bit1 hashes - if (map.bip9_bit0_height != chain_state::map::unrequested) { - auto const bip9_idx = index.get_ancestor(parent_idx, static_cast(map.bip9_bit0_height)); - data.bip9_bit0_hash = (bip9_idx != header_index::null_index) - ? index.get_hash(bip9_idx) - : null_hash; - } else { - data.bip9_bit0_hash = null_hash; - } - - if (map.bip9_bit1_height != chain_state::map::unrequested) { - auto const bip9_idx = index.get_ancestor(parent_idx, static_cast(map.bip9_bit1_height)); - data.bip9_bit1_hash = (bip9_idx != header_index::null_index) - ? index.get_hash(bip9_idx) - : null_hash; - } else { - data.bip9_bit1_hash = null_hash; - } -#endif - -#if defined(KTH_CURRENCY_BCH) - // ABLA state - we don't have block size during header validation - // Initialize with default values; actual block size validation happens during block sync - data.abla_state = domain::chain::abla::state(settings_.abla_config, static_max_block_size(network_)); -#endif - - return data; -} - -code validate_header::accept_full(domain::chain::header const& header, - hash_digest const& hash, - size_t height, - header_index::index_t parent_idx, - header_index const& index) const { - // Basic chain continuity check - if (parent_idx != header_index::null_index) { - auto const expected_prev = index.get_prev_block_hash(parent_idx); - // parent_idx points to the parent header, so we need to check the parent's hash - auto const parent_hash = index.get_hash(parent_idx); - if (header.previous_block_hash() != parent_hash) { - return error::store_block_missing_parent; - } - } else if (height != 0) { - // Non-genesis block without parent - return error::store_block_missing_parent; - } - - // Build chain_state data from header_index - auto data_result = build_chain_state_data(height, header, hash, parent_idx, index); - if (!data_result) { - spdlog::error("[validate_header] accept_full: failed to build chain_state data for height {}", height); - return data_result.error(); - } - - // Create chain_state from the data -#if defined(KTH_CURRENCY_BCH) - auto const anchor = get_asert_anchor_block(); - chain_state state( - std::move(*data_result), - configured_forks_, - checkpoints_, - network_, - anchor, - settings_.asert_half_life, - settings_.abla_config, - leibniz_t(settings_.leibniz_activation_time), - cantor_t(settings_.cantor_activation_time) - ); -#else - chain_state state( - std::move(*data_result), - configured_forks_, - checkpoints_, - network_ - ); -#endif - - // Now perform the full header validation using chain_state - // This is equivalent to header_basis::accept() - - // 1. Difficulty check - if (header.bits() != state.work_required()) { - spdlog::debug("[validate_header] accept_full: incorrect PoW at height {}: " - "header bits={:#x}, required={:#x}", - height, header.bits(), state.work_required()); - return error::incorrect_proof_of_work; - } - - // 2. Checkpoint conflict check - if (state.is_checkpoint_conflict(hash)) { - return error::checkpoints_failed; - } - - // 3. Under checkpoint - skip remaining checks - if (state.is_under_checkpoint()) { - return error::success; - } - - // 4. Version check - if (header.version() < state.minimum_version()) { - spdlog::debug("[validate_header] accept_full: old version at height {}: " - "header version={}, minimum={}", - height, header.version(), state.minimum_version()); - return error::old_version_block; - } - - // 5. Median time past check - if (header.timestamp() <= state.median_time_past()) { - spdlog::debug("[validate_header] accept_full: timestamp too early at height {}: " - "header timestamp={}, MTP={}", - height, header.timestamp(), state.median_time_past()); - return error::timestamp_too_early; - } - - return error::success; -} - -// ============================================================================= -// Static validation functions (pure, no side effects) -// ============================================================================= - -code validate_header::accept_header( - domain::chain::header const& header, - hash_digest const& hash, - domain::chain::chain_state const& state) { - - // 1. Difficulty check - if (header.bits() != state.work_required()) { - return error::incorrect_proof_of_work; - } - - // 2. Checkpoint conflict check - if (state.is_checkpoint_conflict(hash)) { - return error::checkpoints_failed; - } - - // 3. Under checkpoint - skip remaining checks - if (state.is_under_checkpoint()) { - return error::success; - } - - // 4. Version check - if (header.version() < state.minimum_version()) { - return error::old_version_block; - } - - // 5. Median time past check - if (header.timestamp() <= state.median_time_past()) { - return error::timestamp_too_early; - } - - return error::success; -} - } // namespace kth::blockchain diff --git a/src/blockchain/test/block_index_bench/benchmarks.cpp b/src/blockchain/test/block_index_bench/benchmarks.cpp index 400fd933..19e54e5b 100644 --- a/src/blockchain/test/block_index_bench/benchmarks.cpp +++ b/src/blockchain/test/block_index_bench/benchmarks.cpp @@ -3960,7 +3960,7 @@ void test_soa_traversal_unlock_after_lookup() { for (size_t t = 0; t < num_traversers; ++t) { threads.emplace_back([&store, &cached_indices, &stop, &traverse_count, t, traversal_depth] { std::mt19937 rng(t); - std::uniform_int_distribution dist(size_t(traversal_depth), cached_indices.size() - 1); + std::uniform_int_distribution dist(static_cast(traversal_depth), cached_indices.size() - 1); while (!stop.load(std::memory_order_relaxed)) { // Use CACHED index - no lock, no synchronization with writers! uint32_t start_idx = cached_indices[dist(rng)]; diff --git a/src/c-api/src/node.cpp b/src/c-api/src/node.cpp index 19bbf6be..0d5dca0c 100644 --- a/src/c-api/src/node.cpp +++ b/src/c-api/src/node.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -54,42 +55,48 @@ int kth_node_initchain(kth_node_t node) { #if ! defined(KTH_DB_READONLY) void kth_node_init_run_and_wait_for_signal(kth_node_t node, void* ctx, kth_start_modules_t mods, kth_run_handler_t handler) { - // Start node - auto ec = kth_node_cpp(node).start(); - if (handler != nullptr) { - handler(node, ctx, kth::to_c_err(ec)); - } - - if (ec == kth::error::success) { - // Wait for signal - kth_node_cpp(node).wait_for_stop_signal(); - // Stop node - kth_node_cpp(node).stop(); - } + kth_node_cpp(node).init_run_and_wait_for_signal( + version(), + kth::start_modules_to_cpp(mods), + [node, ctx, handler](std::error_code const& ec) { + if (handler != nullptr) { + handler(node, ctx, kth::to_c_err(ec)); + } + }); } void kth_node_init_run(kth_node_t node, void* ctx, kth_start_modules_t mods, kth_run_handler_t handler) { - kth_node_cpp(node).start_async([node, ctx, handler](kth::code ec) { - if (handler != nullptr) { - handler(node, ctx, kth::to_c_err(ec)); - } + kth_node_cpp(node).init_run(version(), kth::start_modules_to_cpp(mods), + [node, ctx, handler](std::error_code const& ec) { + if (handler != nullptr) { + handler(node, ctx, kth::to_c_err(ec)); + } }); } kth_error_code_t kth_node_init_run_sync(kth_node_t node, kth_start_modules_t mods) { - auto ec = kth_node_cpp(node).start(); - return kth::to_c_err(ec); + std::latch latch(1); //Note: workaround to fix an error on some versions of Boost.Threads + kth_error_code_t res; + + kth_node_cpp(node).init_run(version(), kth::start_modules_to_cpp(mods), + [&](std::error_code const& ec) { + res = kth::to_c_err(ec); + latch.count_down(); + } + ); + + latch.wait(); + return res; } #endif // ! defined(KTH_DB_READONLY) void kth_node_signal_stop(kth_node_t node) { - kth_node_cpp(node).stop_async(); + kth_node_cpp(node).signal_stop(); } int kth_node_close(kth_node_t node) { - kth_node_cpp(node).stop(); - return 1; // Success + return kth_node_cpp(node).close(); } int kth_node_stopped(kth_node_t node) { diff --git a/src/consensus/src/bch-rules/coins.h b/src/consensus/src/bch-rules/coins.h index 71514e09..680c63da 100644 --- a/src/consensus/src/bch-rules/coins.h +++ b/src/consensus/src/bch-rules/coins.h @@ -109,7 +109,7 @@ struct hash { } }; } -// return size_t(SipHashUint256Extra(k0(), k1(), o.GetTxId(), o.GetN())); +// return static_cast(SipHashUint256Extra(k0(), k1(), o.GetTxId(), o.GetN())); /** Cursor for iterating over CoinsView state */ class CCoinsViewCursor { diff --git a/src/consensus/src/bch-rules/script/interpreter.cpp b/src/consensus/src/bch-rules/script/interpreter.cpp index a5e128af..721f8335 100644 --- a/src/consensus/src/bch-rules/script/interpreter.cpp +++ b/src/consensus/src/bch-rules/script/interpreter.cpp @@ -59,7 +59,7 @@ int FindAndDelete(CScript &script, const CScript &b) { opcodetype opcode; do { result.insert(result.end(), pc2, pc); - while (size_t(end - pc) >= b.size() && + while (static_cast(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; diff --git a/src/consensus/src/bch-rules/util/strencodings.h b/src/consensus/src/bch-rules/util/strencodings.h index 1fe1853c..17356dd8 100644 --- a/src/consensus/src/bch-rules/util/strencodings.h +++ b/src/consensus/src/bch-rules/util/strencodings.h @@ -252,7 +252,7 @@ bool ConvertBits(const O &outfn, I it, I end) { constexpr size_t maxv = (size_t{1} << tobits) - 1u; constexpr size_t max_acc = (size_t{1} << (frombits + tobits - 1u)) - 1u; while (it != end) { - acc = ((acc << frombits) | size_t(*it)) & max_acc; + acc = ((acc << frombits) | static_cast(*it)) & max_acc; bits += frombits; while (bits >= tobits) { bits -= tobits; diff --git a/src/consensus/src/btc-rules/script/interpreter.cpp b/src/consensus/src/btc-rules/script/interpreter.cpp index ea566062..e636de5a 100644 --- a/src/consensus/src/btc-rules/script/interpreter.cpp +++ b/src/consensus/src/btc-rules/script/interpreter.cpp @@ -260,7 +260,7 @@ int FindAndDelete(CScript& script, const CScript& b) do { result.insert(result.end(), pc2, pc); - while (size_t(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) + while (static_cast(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; diff --git a/src/database/include/kth/database/databases/internal_database.ipp b/src/database/include/kth/database/databases/internal_database.ipp index 4ff6bd0d..f9168491 100644 --- a/src/database/include/kth/database/databases/internal_database.ipp +++ b/src/database/include/kth/database/databases/internal_database.ipp @@ -1103,16 +1103,9 @@ template result_code internal_database_basis::push_block(domain::chain::block const& block, uint32_t height, uint32_t median_time_past, bool insert_reorg, KTH_DB_txn* db_txn) { //precondition: block.transactions().size() >= 1 - result_code res = result_code::success; - - // With headers-first sync, header usually already exists. - // Only write header if it doesn't exist (for backward compatibility/edge cases). - auto existing_header = get_header(height, db_txn); - if ( ! existing_header.has_value()) { - res = push_block_header(block, height, db_txn); - if (res != result_code::success) { - return res; - } + auto res = push_block_header(block, height, db_txn); + if (res != result_code::success) { + return res; } auto const& txs = block.transactions(); diff --git a/src/domain/include/kth/domain/chain/block.hpp b/src/domain/include/kth/domain/chain/block.hpp index b16de53c..23955c39 100644 --- a/src/domain/include/kth/domain/chain/block.hpp +++ b/src/domain/include/kth/domain/chain/block.hpp @@ -144,10 +144,9 @@ struct KD_API block : block_basis { size_t total_inputs(bool with_coinbase = true) const; code check() const; - - /// Check block body only (skip header validation for headers-first sync). - /// Use this when headers have already been validated during header sync. - code check_body() const; + code accept(bool transactions = true) const; + code accept(chain_state const& state, bool transactions = true) const; + code connect() const; // THIS IS FOR LIBRARY USE ONLY, DO NOT CREATE A DEPENDENCY ON IT. mutable validation_t validation{}; diff --git a/src/domain/include/kth/domain/chain/block_basis.hpp b/src/domain/include/kth/domain/chain/block_basis.hpp index eb0ed01a..24cf1b5c 100644 --- a/src/domain/include/kth/domain/chain/block_basis.hpp +++ b/src/domain/include/kth/domain/chain/block_basis.hpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -158,13 +159,20 @@ struct KD_API block_basis { [[nodiscard]] code check(size_t serialized_size_false) const; - /// Check block body only (skip header validation for headers-first sync). - /// Use this when headers have already been validated during header sync. [[nodiscard]] - code check_body(size_t serialized_size_false) const; + code check_transactions() const; [[nodiscard]] - code check_transactions() const; + code accept(chain_state const& state, size_t serialized_size, bool transactions = true) const; + + [[nodiscard]] + code accept_transactions(chain_state const& state) const; + + [[nodiscard]] + code connect(chain_state const& state) const; + + [[nodiscard]] + code connect_transactions(chain_state const& state) const; // protected: void reset(); diff --git a/src/domain/include/kth/domain/chain/header.hpp b/src/domain/include/kth/domain/chain/header.hpp index b4e4eebd..a38256aa 100644 --- a/src/domain/include/kth/domain/chain/header.hpp +++ b/src/domain/include/kth/domain/chain/header.hpp @@ -106,6 +106,8 @@ struct KD_API header : header_basis, hash_memoizer

{ bool is_valid_proof_of_work(bool retarget = true) const; code check(bool retarget = false) const; + code accept(chain_state const& state) const; + // THIS IS FOR LIBRARY USE ONLY, DO NOT CREATE A DEPENDENCY ON IT. mutable validation_t validation{}; diff --git a/src/domain/include/kth/domain/chain/header_basis.hpp b/src/domain/include/kth/domain/chain/header_basis.hpp index e3d19cc1..2a8fef51 100644 --- a/src/domain/include/kth/domain/chain/header_basis.hpp +++ b/src/domain/include/kth/domain/chain/header_basis.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -148,6 +149,9 @@ struct KD_API header_basis { [[nodiscard]] code check(hash_digest const& hash, bool retarget = false) const; + [[nodiscard]] + code accept(::kth::domain::chain::chain_state const& state, hash_digest const& hash) const; + void reset(); private: diff --git a/src/domain/include/kth/domain/config/parser.hpp b/src/domain/include/kth/domain/config/parser.hpp index 8329d5cc..ed40c425 100644 --- a/src/domain/include/kth/domain/config/parser.hpp +++ b/src/domain/include/kth/domain/config/parser.hpp @@ -215,7 +215,7 @@ kth::infrastructure::config::checkpoint::list default_checkpoints(config::networ checkpoints.emplace_back("0000000017d92f88ed2c81885c57f999184860a042250510be06b3edd12e0dc5", 232000); } else if (network == domain::config::network::mainnet) { - checkpoints.reserve(64); + checkpoints.reserve(60); checkpoints.emplace_back("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 0); checkpoints.emplace_back("0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d", 11'111); checkpoints.emplace_back("000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6", 33'333); @@ -340,11 +340,6 @@ kth::infrastructure::config::checkpoint::list default_checkpoints(config::networ checkpoints.emplace_back("00000000000000000157a0a3dcdc80f1acd809648d238c1e893b26247091b3b4", 898'374); checkpoints.emplace_back("0000000000000000007e2e7dd49323c90d16fd76a521804d709f0d5a442fd42a", 898'375); - checkpoints.emplace_back("000000000000000000ff9445c5039fd67d02e901b3cefe8bd55c1d6afb5fe1cf", 900'000); - checkpoints.emplace_back("000000000000000000a2f9b4d4d79f527a664a9932bb1e3f6016ff66a438c302", 910'000); - checkpoints.emplace_back("0000000000000000016a9d52a9c0a7d7fd3cf1a7cea538565674613a65341186", 920'000); - checkpoints.emplace_back("000000000000000000ee3232281f632df96f4222361d564af0fc2e3da352e34f", 930'000); - // //2026-May Upgrade - leibniz - (1778846400) // checkpoints.emplace_back("", 0); // checkpoints.emplace_back("", 0); diff --git a/src/domain/include/kth/domain/constants/common.hpp b/src/domain/include/kth/domain/constants/common.hpp index ebc95755..53adc4e4 100644 --- a/src/domain/include/kth/domain/constants/common.hpp +++ b/src/domain/include/kth/domain/constants/common.hpp @@ -8,7 +8,14 @@ #include #include -#include +// #include +// #include + +// #include +// #include +// #include +// #include +// #include namespace kth { diff --git a/src/domain/include/kth/domain/impl/machine/interpreter.ipp b/src/domain/include/kth/domain/impl/machine/interpreter.ipp index 857c1245..5ed16340 100644 --- a/src/domain/include/kth/domain/impl/machine/interpreter.ipp +++ b/src/domain/include/kth/domain/impl/machine/interpreter.ipp @@ -1706,7 +1706,7 @@ interpreter::result interpreter::op_active_bytecode(program& program) { auto const script_end = program.end(); // Calculate the size of the active bytecode - auto const script_size = size_t(script_end - begin_code_hash); + auto const script_size = static_cast(script_end - begin_code_hash); // Check maximum script element size constraint auto const max_script_element_size = program.max_script_element_size(); diff --git a/src/domain/src/chain/block.cpp b/src/domain/src/chain/block.cpp index 64513eed..c7035f0a 100644 --- a/src/domain/src/chain/block.cpp +++ b/src/domain/src/chain/block.cpp @@ -340,7 +340,7 @@ size_t block::locator_size(size_t top) { if (remaining < 2) { return top + size_t{1}; } - return first_ten_or_top + size_t(std::log2(remaining) + 0.5) + size_t{1}; + return first_ten_or_top + static_cast(std::log2(remaining) + 0.5) + size_t{1}; } // This algorithm is a network best practice, not a consensus rule. @@ -429,10 +429,20 @@ code block::check() const { return block_basis::check(serialized_size()); } -// Check block body only (skip header validation for headers-first sync). -code block::check_body() const { - validation.start_check = asio::steady_clock::now(); - return block_basis::check_body(serialized_size()); +code block::accept(bool transactions) const { + auto const state = validation.state; + return state ? accept(*state, transactions) : error::operation_failed; +} + +// These checks assume that prevout caching is completed on all tx.inputs. +code block::accept(chain_state const& state, bool transactions) const { + validation.start_accept = asio::steady_clock::now(); + return block_basis::accept(state, serialized_size(), transactions); +} + +code block::connect() const { + auto const state = validation.state; + return state ? block_basis::connect(*state) : error::operation_failed; } } // namespace kth::domain::chain diff --git a/src/domain/src/chain/block_basis.cpp b/src/domain/src/chain/block_basis.cpp index cfbe0ade..df1d8852 100644 --- a/src/domain/src/chain/block_basis.cpp +++ b/src/domain/src/chain/block_basis.cpp @@ -18,12 +18,14 @@ #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -42,6 +44,7 @@ namespace kth::domain::chain { +using namespace kth::domain::machine; using namespace boost::adaptors; // Constructors. @@ -438,6 +441,26 @@ code block_basis::check_transactions() const { return error::success; } +code block_basis::accept_transactions(chain_state const& state) const { + code ec; + for (auto const& tx : transactions_) { + if ( ! tx.validation.validated && (ec = tx.accept(state, false))) { + return ec; + } + } + return error::success; +} + +code block_basis::connect_transactions(chain_state const& state) const { + code ec; + for (auto const& tx : transactions_) { + if ( ! tx.validation.validated && (ec = tx.connect(state))) { + return ec; + } + } + return error::success; +} + // Validation. //----------------------------------------------------------------------------- @@ -447,14 +470,10 @@ code block_basis::check(size_t serialized_size_false) const { if ((ec = header_.check())) { return ec; - } - return check_body(serialized_size_false); -} + // TODO(legacy): relates to total of tx.size(false) (pool cache). -> no witness size + } -// Check block body only (skip header validation for headers-first sync). -// Use this when headers have already been validated during header sync. -code block_basis::check_body(size_t serialized_size_false) const { if (serialized_size_false > static_absolute_max_block_size()) { return error::block_size_limit; } @@ -469,27 +488,132 @@ code block_basis::check_body(size_t serialized_size_false) const { if (is_extra_coinbases()) { return error::extra_coinbases; + // TODO(legacy): determinable from tx pool graph. } #if ! defined(KTH_CURRENCY_BCH) // BTC and LTC - // Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) - // and for BitcoinCash (BCH) before 2018-Nov-15. + //Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) + // and for BitcoinCash (BCH) before 2018-Nov-15. if (is_forward_reference()) { return error::forward_reference; } #endif + + // This is subset of is_internal_double_spend if collisions cannot happen. + ////else if ( ! is_distinct_transaction_set()) + //// return error::internal_duplicate; + + // TODO(legacy): determinable from tx pool graph. if (is_internal_double_spend()) { return error::block_internal_double_spend; + // TODO(legacy): relates height to tx.hash(false) (pool cache). } if ( ! is_valid_merkle_root()) { return error::merkle_mismatch; + + // We cannot know if bip16 is enabled at this point so we disable it. + // This will not make a difference unless prevouts are populated, in which + // case they are ignored. This means that p2sh sigops are not counted here. + // This is a preliminary check, the final count must come from connect(). + // Reenable once sigop caching is implemented, otherwise is deoptimization. + ////else if (signature_operations(false, false) > get_max_block_sigops()) + //// return error::block_legacy_sigop_limit; } return check_transactions(); } +// These checks assume that prevout caching is completed on all tx.inputs. + + +code block_basis::accept(chain_state const& state, size_t serialized_size, bool transactions) const { + auto const bip16 = state.is_enabled(rule_fork::bip16_rule); + auto const bip34 = state.is_enabled(rule_fork::bip34_rule); + auto const bip113 = state.is_enabled(rule_fork::bip113_rule); + auto const bip141 = false; // No segwit + + code ec; + if ((ec = header_.accept(state))) { + return ec; + } + + if (state.is_lobachevski_enabled()) { + if (serialized_size > state.dynamic_max_block_size()) { + return error::block_size_limit; + } + } else if (state.is_pythagoras_enabled()) { + if (serialized_size > static_max_block_size(state.network())) { + return error::block_size_limit; + } + } else { + if (serialized_size > max_block_size::mainnet_old) { + return error::block_size_limit; + } + } + + if (state.is_under_checkpoint()) { + return error::success; + } + + + //Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) + // and for BitcoinCash (BCH) before 2018-Nov-15. + + if (state.is_euclid_enabled()) { + if ( ! is_canonical_ordered()) { + return error::non_canonical_ordered; + } + } else { + if (is_forward_reference()) { + return error::forward_reference; + } + } + + if (bip34 && !is_valid_coinbase_script(state.height())) { + return error::coinbase_height_mismatch; + } + + // TODO(legacy): relates height to total of tx.fee (pool cach). + if ( ! is_valid_coinbase_claim(state.height())) { + return error::coinbase_value_limit; + } + + // TODO(legacy): relates median time past to tx.locktime (pool cache min tx.time). + auto const block_time = bip113 ? state.median_time_past() : header_.timestamp(); + if ( ! is_final(state.height(), block_time)) { + return error::block_non_final; + } + +#if defined(KTH_CURRENCY_BCH) + if ( ! state.is_fermat_enabled()) { +#endif + // TODO(legacy): determine if performance benefit is worth excluding sigops here. + // TODO(legacy): relates block limit to total of tx.sigops (pool cache tx.sigops). + // This recomputes sigops to include p2sh from prevouts. + size_t const allowed_sigops = get_allowed_sigops(serialized_size); + if (transactions && (signature_operations(bip16, bip141) > allowed_sigops)) { + return error::block_embedded_sigop_limit; + } +#if defined(KTH_CURRENCY_BCH) + } +#endif + + if (transactions) { + return accept_transactions(state); + } + + return ec; +} + +code block_basis::connect(chain_state const& state) const { + if (state.is_under_checkpoint()) { + return error::success; + } + return connect_transactions(state); +} + // Non-member functions. //----------------------------------------------------------------------------- @@ -502,7 +626,7 @@ size_t locator_size(size_t top) { auto const first_ten_or_top = std::min(size_t(10), top); auto const remaining = top - first_ten_or_top; auto const back_off = remaining == 0 ? 0.0 : remaining == 1 ? 1.0 : std::log2(remaining); - auto const rounded_up_log = size_t(std::nearbyint(back_off)); + auto const rounded_up_log = static_cast(std::nearbyint(back_off)); return first_ten_or_top + rounded_up_log + size_t(1); } diff --git a/src/domain/src/chain/chain_state.cpp b/src/domain/src/chain/chain_state.cpp index 2c2da846..87d027a2 100644 --- a/src/domain/src/chain/chain_state.cpp +++ b/src/domain/src/chain/chain_state.cpp @@ -906,7 +906,7 @@ auto timestamps_position(chain_state::timestamps const& times, size_t last_n = m std::vector timestamps_subset(chain_state::timestamps const& times, size_t last_n = median_time_past_interval) { auto at = timestamps_position(times, last_n); - auto n = (std::min)(size_t(std::distance(at, times.end())), median_time_past_interval); + auto n = (std::min)(static_cast(std::distance(at, times.end())), median_time_past_interval); std::vector subset(n); std::copy_n(at, n, subset.begin()); return subset; diff --git a/src/domain/src/chain/header.cpp b/src/domain/src/chain/header.cpp index c34573bb..753505d8 100644 --- a/src/domain/src/chain/header.cpp +++ b/src/domain/src/chain/header.cpp @@ -148,4 +148,8 @@ code header::check(bool retarget) const { return header_basis::check(hash_pow(), retarget); } +code header::accept(chain_state const& state) const { + return header_basis::accept(state, hash_pow()); +} + } // namespace kth::domain::chain diff --git a/src/domain/src/chain/header_basis.cpp b/src/domain/src/chain/header_basis.cpp index a2d48151..fa3dc672 100644 --- a/src/domain/src/chain/header_basis.cpp +++ b/src/domain/src/chain/header_basis.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -267,4 +268,28 @@ code header_basis::check(hash_digest const& hash, bool retarget) const { return error::success; } +code header_basis::accept(chain_state const& state, hash_digest const& hash) const { + if (bits_ != state.work_required()) { + return error::incorrect_proof_of_work; + } + + if (state.is_checkpoint_conflict(hash)) { + return error::checkpoints_failed; + } + + if (state.is_under_checkpoint()) { + return error::success; + } + + if (version_ < state.minimum_version()) { + return error::old_version_block; + } + + if (timestamp_ <= state.median_time_past()) { + return error::timestamp_too_early; + } + + return error::success; +} + } // namespace kth::domain::chain diff --git a/src/infrastructure/include/kth/infrastructure.hpp b/src/infrastructure/include/kth/infrastructure.hpp index 389564ef..17ffb776 100644 --- a/src/infrastructure/include/kth/infrastructure.hpp +++ b/src/infrastructure/include/kth/infrastructure.hpp @@ -112,8 +112,6 @@ #include #include #include -#include -#include #include #include diff --git a/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp b/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp index 75e460e3..9a5874b3 100644 --- a/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp +++ b/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp @@ -228,7 +228,7 @@ size_t serializer::read_size_big_endian() { // This facilitates safely passing the size into a follow-on writer. // Return zero allows follow-on use before testing reader state. if (size <= max_size_t) { - return size_t(size); + return static_cast(size); } valid_ = false; @@ -259,7 +259,7 @@ size_t serializer::read_size_little_endian() { // This facilitates safely passing the size into a follow-on writer. // Return zero allows follow-on use before testing reader state. if (size <= max_size_t) { - return size_t(size); + return static_cast(size); } valid_ = false; diff --git a/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp b/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp deleted file mode 100644 index 5da36b06..00000000 --- a/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP -#define KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP - -#include -#include -#include -#include - -#include - -namespace kth { - -// ============================================================================= -// CPU Executor (Dedicated Thread Pool for CPU-Bound Work) -// ============================================================================= -// -// A specialized executor for CPU-bound operations that should not block the -// IO thread pool. This separates IO-bound async operations from CPU-intensive -// work like block validation, transaction verification, and cryptographic ops. -// -// Key properties: -// - Separate thread pool from IO operations -// - Sized to match hardware concurrency by default -// - Async interface via awaitable for seamless coroutine integration -// - Work can be posted from any thread -// -// Usage in coroutines: -// cpu_executor cpu; -// -// awaitable validate_block(block_ptr block) { -// // Offload CPU-intensive validation to CPU pool -// bool valid = co_await cpu.execute([&block]() { -// return block->is_valid(); // Runs on CPU pool thread -// }); -// -// if (!valid) { -// throw validation_error("Invalid block"); -// } -// } -// -// Architecture: -// ┌─────────────────┐ ┌─────────────────┐ -// │ IO Thread Pool │ │ CPU Thread Pool │ -// │ (network I/O) │ │ (validation) │ -// │ │ │ │ -// │ peer1.run() │ │ validate() │ -// │ peer2.run() │ ───► │ verify_sig() │ -// │ accept_loop() │ │ hash_block() │ -// │ ... │ │ ... │ -// └─────────────────┘ └─────────────────┘ -// -// ============================================================================= - -class cpu_executor { -public: - // Construct with specified number of threads - // Default: hardware_concurrency (number of CPU cores) - explicit cpu_executor(size_t threads = std::thread::hardware_concurrency()) - : pool_(threads > 0 ? threads : 1) - {} - - // Non-copyable, non-movable - cpu_executor(cpu_executor const&) = delete; - cpu_executor& operator=(cpu_executor const&) = delete; - cpu_executor(cpu_executor&&) = delete; - cpu_executor& operator=(cpu_executor&&) = delete; - - ~cpu_executor() { - stop(); - join(); - } - - // Execute a callable on the CPU pool and return result via awaitable. - // This is the primary interface for offloading CPU work from coroutines. - // - // Example: - // auto result = co_await cpu.execute([]() { - // return expensive_computation(); - // }); - // - template - auto execute(F&& work) -> ::asio::awaitable> { - using result_type = std::invoke_result_t; - - co_return co_await ::asio::co_spawn( - pool_.get_executor(), - [w = std::forward(work)]() -> ::asio::awaitable { - if constexpr (std::is_void_v) { - std::invoke(std::move(w)); - co_return; - } else { - co_return std::invoke(std::move(w)); - } - }, - ::asio::use_awaitable - ); - } - - // Post work to the CPU pool without waiting for result. - // Use when you don't need the result in the calling coroutine. - template - void post(F&& work) { - ::asio::post(pool_.get_executor(), std::forward(work)); - } - - // Get the underlying executor for advanced use cases - [[nodiscard]] - auto get_executor() { - return pool_.get_executor(); - } - - // Stop accepting new work - void stop() { - pool_.stop(); - } - - // Wait for all work to complete - void join() { - pool_.join(); - } - - // Get number of threads in the pool - [[nodiscard]] - size_t thread_count() const noexcept { - return thread_count_; - } - -private: - ::asio::thread_pool pool_; - size_t thread_count_{std::thread::hardware_concurrency()}; -}; - -// ============================================================================= -// Global CPU Executor Access -// ============================================================================= -// -// For convenience, a global CPU executor can be used. However, prefer passing -// the executor explicitly for better testability and control. -// -// Usage: -// auto& cpu = kth::global_cpu_executor(); -// co_await cpu.execute([]() { ... }); -// -// ============================================================================= - -inline cpu_executor& global_cpu_executor() { - static cpu_executor instance; - return instance; -} - -} // namespace kth - -#endif // KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp b/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp index 07d9271a..ee927a0c 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp @@ -74,7 +74,7 @@ struct KI_API pseudo_random { //TODO: replace exceptions with std::expected throw std::runtime_error("getrandom() failed, errno=" + std::to_string(errno)); } - offset += size_t(ret); + offset += static_cast(ret); } #endif } diff --git a/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp deleted file mode 100644 index 1ad32279..00000000 --- a/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_INFRASTRUCTURE_TASK_GROUP_HPP -#define KTH_INFRASTRUCTURE_TASK_GROUP_HPP - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace kth { - -// ============================================================================= -// Task Group (Nursery Pattern for Structured Concurrency) -// ============================================================================= -// -// A task_group manages a set of concurrent coroutines and ensures all complete -// before the group is destroyed. This implements the "nursery" pattern from -// structured concurrency (similar to Trio in Python or Kotlin coroutines). -// -// Key properties: -// - All spawned tasks are tracked automatically -// - join() waits for ALL tasks to complete -// - No tasks are "lost" or detached -// - Exception in any task can be propagated (future enhancement) -// -// Usage: -// task_group tasks(executor); -// -// tasks.spawn([&]() -> awaitable { -// co_await do_work_1(); -// }); -// -// tasks.spawn([&]() -> awaitable { -// co_await do_work_2(); -// }); -// -// co_await tasks.join(); // Waits for both tasks -// -// Integration with structured concurrency: -// awaitable parent_task() { -// task_group children(co_await this_coro::executor); -// -// children.spawn(child_1()); -// children.spawn(child_2()); -// -// co_await children.join(); // Parent waits for all children -// } -// -// ============================================================================= - -class task_group { -public: - explicit task_group(::asio::any_io_executor executor) - : executor_(std::move(executor)) - , done_channel_(executor_, 1) - {} - - // Non-copyable, non-movable (prevents accidental misuse) - task_group(task_group const&) = delete; - task_group& operator=(task_group const&) = delete; - task_group(task_group&&) = delete; - task_group& operator=(task_group&&) = delete; - - ~task_group() { - // In debug builds, assert that join() was called - // In release, just log a warning if tasks are still active - if (active_count_.load() > 0) { - // Tasks still running - this is a programming error - // The destructor should only be called after join() - } - } - - // Spawn a coroutine into the group. - // The coroutine will be tracked and join() will wait for it. - // Note: This uses ONE internal detached spawn, but the task is tracked. - // - // Accepts either: - // - An awaitable directly: tasks.spawn(some_coro()) - // - A callable returning awaitable: tasks.spawn([&]() -> awaitable { ... }) - template - void spawn(Coro&& coro) { - ++active_count_; - ++total_spawned_; - - ::asio::co_spawn(executor_, - [this, c = std::forward(coro)]() mutable -> ::asio::awaitable { - try { - if constexpr (std::is_invocable_v) { - // It's a callable (lambda, function) - invoke it to get the awaitable - co_await std::invoke(std::move(c)); - } else { - // It's already an awaitable - just await it directly - co_await std::move(c); - } - } catch (...) { - // TODO: Store exception for later propagation - // For now, just decrement and signal - } - decrement_and_signal(); - }, - ::asio::detached); // Single controlled detached point - } - - // Wait for all spawned tasks to complete. - // This MUST be called before the task_group is destroyed. - [[nodiscard]] - ::asio::awaitable join() { - if (active_count_.load() == 0) { - co_return; - } - - // Wait for signal that all tasks completed - auto [ec] = co_await done_channel_.async_receive( - ::asio::as_tuple(::asio::use_awaitable)); - - // Channel closed or received signal - all tasks done - co_return; - } - - // Check if there are active tasks - [[nodiscard]] - bool has_active_tasks() const noexcept { - return active_count_.load() > 0; - } - - // Get number of currently active tasks - [[nodiscard]] - size_t active_count() const noexcept { - return active_count_.load(); - } - - // Get total number of tasks spawned (including completed) - [[nodiscard]] - size_t total_spawned() const noexcept { - return total_spawned_.load(); - } - -private: - void decrement_and_signal() { - auto const prev = active_count_.fetch_sub(1); - if (prev == 1) { - // We were the last task - signal completion - // Use try_send to avoid blocking if no one is waiting yet - done_channel_.try_send(std::error_code{}); - } - } - - ::asio::any_io_executor executor_; - std::atomic active_count_{0}; - std::atomic total_spawned_{0}; - - // Channel to signal when all tasks complete - // Capacity of 1 is sufficient - we only send once when count hits 0 - concurrent_event_channel done_channel_; -}; - -// ============================================================================= -// Scoped Task Group (RAII wrapper) -// ============================================================================= -// -// Automatically joins on scope exit. Useful for ensuring structured concurrency -// even when exceptions occur. -// -// Usage: -// { -// scoped_task_group tasks(executor); -// tasks.spawn(work_1()); -// tasks.spawn(work_2()); -// } // Automatically waits here (blocking!) -// -// WARNING: The destructor blocks! Use with care. -// Prefer explicit co_await join() in coroutines. -// -// ============================================================================= - -class scoped_task_group { -public: - explicit scoped_task_group(::asio::any_io_executor executor) - : executor_(executor) - , group_(std::move(executor)) - {} - - ~scoped_task_group() { - if (group_.has_active_tasks()) { - // Block until all tasks complete - // This is a blocking call - use sparingly! - std::promise done; - auto future = done.get_future(); - - ::asio::co_spawn(executor_, - [this, &done]() -> ::asio::awaitable { - co_await group_.join(); - done.set_value(); - }, - ::asio::detached); - - future.wait(); - } - } - - template - void spawn(Coro&& coro) { - group_.spawn(std::forward(coro)); - } - - [[nodiscard]] - ::asio::awaitable join() { - return group_.join(); - } - - [[nodiscard]] size_t active_count() const noexcept { - return group_.active_count(); - } - -private: - ::asio::any_io_executor executor_; - task_group group_; -}; - -} // namespace kth - -#endif // KTH_INFRASTRUCTURE_TASK_GROUP_HPP diff --git a/src/infrastructure/src/log/sink.cpp b/src/infrastructure/src/log/sink.cpp index 14892309..8022fc36 100644 --- a/src/infrastructure/src/log/sink.cpp +++ b/src/infrastructure/src/log/sink.cpp @@ -11,25 +11,24 @@ namespace kth::log { -void initialize(std::string const& debug_file, [[maybe_unused]] std::string const& error_file, bool stdout_enabled, bool verbose) { +void initialize(std::string const& debug_file, std::string const& error_file, bool stdout_enabled, bool verbose) { try { auto debug_file_sink = std::make_shared(debug_file, true); - // Debug file captures debug+ normally, or trace+ when verbose debug_file_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + auto error_file_sink = std::make_shared(error_file, true); + error_file_sink->set_level(spdlog::level::err); + if (stdout_enabled) { auto stdout_sink = std::make_shared(); stdout_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::info); - auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, stdout_sink})); - // Logger level must be trace so all messages reach the debug file sink. - // Each sink filters independently based on its own level. - logger->set_level(spdlog::level::trace); + auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink, stdout_sink})); + logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); logger->flush_on(spdlog::level::info); spdlog::set_default_logger(logger); } else { - auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink})); - // Logger level must be trace so all messages reach the debug file sink. - logger->set_level(spdlog::level::trace); + auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink})); + logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); logger->flush_on(spdlog::level::debug); spdlog::set_default_logger(logger); } diff --git a/src/infrastructure/src/unicode/unicode_streambuf.cpp b/src/infrastructure/src/unicode/unicode_streambuf.cpp index 98e00331..12ea7883 100644 --- a/src/infrastructure/src/unicode/unicode_streambuf.cpp +++ b/src/infrastructure/src/unicode/unicode_streambuf.cpp @@ -50,7 +50,7 @@ std::streambuf::int_type unicode_streambuf::underflow() { auto const size = static_cast(wide_size_); // Read from the wide input buffer. - auto const read = size_t(wide_buffer_->sgetn(wide_, size)); + auto const read = static_cast(wide_buffer_->sgetn(wide_, size)); // Handle read termination. if (read == 0) { diff --git a/src/infrastructure/src/utility/png.cpp b/src/infrastructure/src/utility/png.cpp index f6a2e756..fd996e20 100644 --- a/src/infrastructure/src/utility/png.cpp +++ b/src/infrastructure/src/utility/png.cpp @@ -23,7 +23,7 @@ bool png::write_png(byte_span data, uint32_t size, std::ostream& out) { extern "C" void sink_write(png_structp png_ptr, png_bytep data, png_size_t length) { static_assert(sizeof(length) <= sizeof(size_t), "png_size_t too large"); - auto const size = size_t(length); + auto const size = static_cast(length); auto& sink = *reinterpret_cast(png_get_io_ptr(png_ptr)); sink.write_bytes(reinterpret_cast(data), size); } diff --git a/src/infrastructure/src/utility/system_memory.cpp b/src/infrastructure/src/utility/system_memory.cpp index 5d9f64fb..99ed3e31 100644 --- a/src/infrastructure/src/utility/system_memory.cpp +++ b/src/infrastructure/src/utility/system_memory.cpp @@ -34,7 +34,7 @@ size_t get_total_system_memory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { - return size_t(status.ullTotalPhys); + return static_cast(status.ullTotalPhys); } return 0; #elif defined(__APPLE__) @@ -42,14 +42,14 @@ size_t get_total_system_memory() { uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctl(mib, 2, &memsize, &len, nullptr, 0) == 0) { - return size_t(memsize); + return static_cast(memsize); } return 0; #elif defined(__FreeBSD__) uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctlbyname("hw.physmem", &memsize, &len, nullptr, 0) == 0) { - return size_t(memsize); + return static_cast(memsize); } return 0; #elif defined(__linux__) @@ -68,7 +68,7 @@ size_t get_available_system_memory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { - return size_t(status.ullAvailPhys); + return static_cast(status.ullAvailPhys); } return 0; #elif defined(__APPLE__) @@ -84,7 +84,7 @@ size_t get_available_system_memory() { // Available = free + inactive + purgeable (can be reclaimed) uint64_t available = (uint64_t)(vm_stats.free_count + vm_stats.inactive_count + vm_stats.purgeable_count) * page_size; - return size_t(available); + return static_cast(available); } return 0; #elif defined(__FreeBSD__) @@ -97,7 +97,7 @@ size_t get_available_system_memory() { unsigned int inactive_count = 0; len = sizeof(inactive_count); sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_count, &len, nullptr, 0); - return size_t((free_count + inactive_count)) * page_size; + return static_cast((free_count + inactive_count)) * page_size; } return 0; #elif defined(__linux__) @@ -109,7 +109,7 @@ size_t get_available_system_memory() { unsigned long long mem_kb; if (sscanf(line, "MemAvailable: %llu kB", &mem_kb) == 1) { fclose(f); - return size_t(mem_kb * 1024); + return static_cast(mem_kb * 1024); } } fclose(f); @@ -143,7 +143,7 @@ size_t get_resident_memory() { #elif defined(_WIN32) PROCESS_MEMORY_COUNTERS pmc; if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { - return size_t(pmc.WorkingSetSize); + return static_cast(pmc.WorkingSetSize); } return 0; #elif defined(__APPLE__) @@ -157,7 +157,7 @@ size_t get_resident_memory() { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage) == 0) { // ru_maxrss is in kilobytes on FreeBSD - return size_t(usage.ru_maxrss) * 1024; + return static_cast(usage.ru_maxrss) * 1024; } return 0; #elif defined(__linux__) diff --git a/src/network/include/kth/network/p2p_node.hpp b/src/network/include/kth/network/p2p_node.hpp index 5c2d132b..cd41dd22 100644 --- a/src/network/include/kth/network/p2p_node.hpp +++ b/src/network/include/kth/network/p2p_node.hpp @@ -133,31 +133,6 @@ struct connection_result { handshake_result handshake; }; -// ============================================================================= -// Peer event (for peer_supervisor channel) -// ============================================================================= - -enum class peer_direction { - inbound, - outbound -}; - -/// Result of handshake sent back to connect() caller -struct handshake_response { - code result; // error::success or error code -}; - -/// Channel type for handshake response (one-shot) -using handshake_response_channel = concurrent_channel; - -struct peer_event { - peer_session::ptr peer; - peer_direction direction; - // Optional response channel for connect() to wait on handshake result - // If nullptr, no response is expected (e.g., for seeding connections) - std::shared_ptr response_channel; -}; - // ============================================================================= // P2P Node (main networking class) // ============================================================================= @@ -260,9 +235,6 @@ class KN_API p2p_node { ::asio::awaitable run_peer_protocols(peer_session::ptr peer); ::asio::awaitable maintain_outbound_connections(); - // Peer supervisor - manages all peer lifecycles (structured concurrency) - ::asio::awaitable peer_supervisor(); - // Helper for seeding - takes params by value to avoid lambda capture issues ::asio::awaitable connect_to_seed( std::string seed_host, @@ -281,18 +253,10 @@ class KN_API p2p_node { std::atomic stopped_{true}; std::atomic seeded_{false}; - std::atomic supervisor_ready_{false}; // Signals that peer_supervisor is ready kth::atomic top_block_; // Message dispatcher for routing messages to handlers message_dispatcher dispatcher_; - - // Channels for structured concurrency (peer_supervisor pattern) - // New peers are sent here by run_inbound/run_outbound, processed by peer_supervisor - std::unique_ptr> new_peer_channel_; - - // Signal to stop the peer_supervisor gracefully - std::unique_ptr stop_signal_; }; } // namespace kth::network diff --git a/src/network/include/kth/network/peer_session.hpp b/src/network/include/kth/network/peer_session.hpp index 29e004a8..c791d337 100644 --- a/src/network/include/kth/network/peer_session.hpp +++ b/src/network/include/kth/network/peer_session.hpp @@ -126,39 +126,6 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] inbound_channel& messages(); - // ------------------------------------------------------------------------- - // Direct I/O (for handshake before run() starts) - // ------------------------------------------------------------------------- - // These methods read/write directly to the socket without using channels. - // Use ONLY before calling run() - after run() starts, use send() and messages(). - - /// Read a message directly from the socket (bypasses inbound channel) - /// Use this for handshake before run() is started - [[nodiscard]] - awaitable_expected read_message_direct(); - - /// Send a message directly to the socket (bypasses outbound channel) - /// Use this for handshake before run() is started - template - ::asio::awaitable send_direct(Message const& message) { - if (stopped()) { - co_return error::channel_stopped; - } - - auto data = domain::message::serialize(version_.load(), message, protocol_magic_); - auto [ec, bytes_written] = co_await ::asio::async_write( - socket_, - ::asio::buffer(data), - ::asio::as_tuple(::asio::use_awaitable)); - - if (ec) { - co_return error::boost_to_error_code(ec); - } - - bytes_sent_.fetch_add(bytes_written, std::memory_order_relaxed); - co_return error::success; - } - // ------------------------------------------------------------------------- // Response channels (for request/response patterns like getheaders/headers) // ------------------------------------------------------------------------- @@ -265,32 +232,6 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] bool is_preferred_download() const; - // ------------------------------------------------------------------------- - // Statistics (lock-free, benign data races acceptable) - // ------------------------------------------------------------------------- - - /// Get total bytes received from this peer - [[nodiscard]] - size_t bytes_received() const; - - /// Get total bytes sent to this peer - [[nodiscard]] - size_t bytes_sent() const; - - /// Get last ping latency in milliseconds - [[nodiscard]] - uint32_t ping_latency_ms() const; - - /// Record a ping sent (store nonce and time for latency calculation) - void record_ping_sent(uint64_t nonce); - - /// Record a pong received, returns true if nonce matches pending ping - bool record_pong_received(uint64_t nonce); - - /// Get connection time - [[nodiscard]] - std::chrono::steady_clock::time_point connection_time() const; - private: // ------------------------------------------------------------------------- // Internal coroutines @@ -362,18 +303,6 @@ class KN_API peer_session : public std::enable_shared_from_this { std::atomic one_shot_{false}; std::atomic permission_flags_{uint32_t(permission_flags::none)}; - // Statistics (lock-free, benign data races acceptable) - std::atomic bytes_received_{0}; - std::atomic bytes_sent_{0}; - std::atomic ping_latency_ms_{0}; - std::chrono::steady_clock::time_point connection_time_{std::chrono::steady_clock::now()}; - - // Ping tracking (lock-free) - // We store time as nanoseconds since steady_clock epoch for atomic access - // Benign data races are acceptable for statistics - std::atomic pending_ping_nonce_{0}; - std::atomic pending_ping_time_ns_{0}; - // Buffers (only accessed from read_loop, no synchronization needed) data_chunk heading_buffer_; }; diff --git a/src/network/include/kth/network/protocols_coro.hpp b/src/network/include/kth/network/protocols_coro.hpp index f3f7cbee..98d80eb2 100644 --- a/src/network/include/kth/network/protocols_coro.hpp +++ b/src/network/include/kth/network/protocols_coro.hpp @@ -167,23 +167,6 @@ KN_API awaitable_expected perform_handshake( peer_session& peer, handshake_config const& config); -/// Perform version handshake using direct socket I/O (no message pump needed) -/// This version reads/writes directly to the socket, so peer->run() does NOT -/// need to be running. Use this to avoid detached coroutines in connect/accept. -/// -/// Usage: -/// auto peer = co_await async_connect(...); -/// auto result = co_await perform_handshake_direct(*peer, config); // No run() needed! -/// // After handshake, send peer to supervisor which starts run() -/// -/// @param peer The peer session (run() must NOT be running yet) -/// @param config Handshake configuration -/// @return handshake_result on success, error code on failure -[[nodiscard]] -KN_API awaitable_expected perform_handshake_direct( - peer_session& peer, - handshake_config const& config); - /// Create handshake config from network settings [[nodiscard]] KN_API handshake_config make_handshake_config( @@ -298,26 +281,6 @@ KN_API awaitable_expected request_block( hash_digest const& block_hash, std::chrono::seconds timeout); -/// Result of batch block request - block with its height -struct block_with_height { - uint32_t height; - domain::message::block block; -}; - -/// Request multiple blocks in a single getdata (batch mode) -/// Sends ONE getdata with all hashes and receives blocks as they arrive. -/// Much more efficient than requesting blocks one at a time. -/// @param peer The peer session -/// @param blocks Vector of {height, hash} pairs to request -/// @param timeout Maximum time to wait for ALL blocks -/// @return Vector of received blocks with heights, or error -/// @note Blocks may be received out of order; vector is sorted by height on return -[[nodiscard]] -KN_API awaitable_expected> request_blocks_batch( - peer_session& peer, - std::vector> const& blocks, - std::chrono::seconds timeout); - // ----------------------------------------------------------------------------- // Inventory Protocol // ----------------------------------------------------------------------------- diff --git a/src/network/include/kth/network/settings.hpp b/src/network/include/kth/network/settings.hpp index 488d8fda..938f492a 100644 --- a/src/network/include/kth/network/settings.hpp +++ b/src/network/include/kth/network/settings.hpp @@ -42,7 +42,6 @@ struct KN_API settings { uint32_t channel_germination_seconds; uint32_t host_pool_capacity; kth::path hosts_file; - kth::path banlist_file; infrastructure::config::authority self; infrastructure::config::authority::list blacklist; infrastructure::config::endpoint::list peers; diff --git a/src/network/src/banlist.cpp b/src/network/src/banlist.cpp index a6bdc984..be002a86 100644 --- a/src/network/src/banlist.cpp +++ b/src/network/src/banlist.cpp @@ -36,25 +36,8 @@ void banlist::ban( bans_.insert_or_assign(ip, entry); - // Log with human-readable duration - auto const duration_secs = duration.count(); - if (duration_secs >= 365 * 24 * 60 * 60) { - // More than a year = "permanent" - spdlog::info("[banlist] Banned {} permanently, reason: {}", - ip.to_string(), to_string(reason)); - } else if (duration_secs >= 24 * 60 * 60) { - spdlog::info("[banlist] Banned {} for {} days, reason: {}", - ip.to_string(), duration_secs / (24 * 60 * 60), to_string(reason)); - } else if (duration_secs >= 60 * 60) { - spdlog::info("[banlist] Banned {} for {} hours, reason: {}", - ip.to_string(), duration_secs / (60 * 60), to_string(reason)); - } else { - spdlog::info("[banlist] Banned {} for {}s, reason: {}", - ip.to_string(), duration_secs, to_string(reason)); - } - - // Persist to file immediately (bans are rare, so I/O overhead is acceptable) - save(); + spdlog::info("[banlist] Banned {} for {}s, reason: {}", + ip.to_string(), duration.count(), to_string(reason)); } void banlist::ban( @@ -69,7 +52,6 @@ bool banlist::unban(::asio::ip::address const& ip) { auto const erased = bans_.erase(ip); if (erased > 0) { spdlog::info("[banlist] Unbanned {}", ip.to_string()); - save(); // Persist immediately return true; } return false; @@ -112,7 +94,6 @@ size_t banlist::size() const { void banlist::clear() { bans_.clear(); spdlog::info("[banlist] Cleared all bans"); - save(); // Persist immediately } void banlist::sweep_expired() { diff --git a/src/network/src/handlers/pong.cpp b/src/network/src/handlers/pong.cpp index 68f377da..577cc33b 100644 --- a/src/network/src/handlers/pong.cpp +++ b/src/network/src/handlers/pong.cpp @@ -13,14 +13,8 @@ ::asio::awaitable handle( peer_session& peer, domain::message::pong const& msg) { - // Record pong to calculate latency - if (peer.record_pong_received(msg.nonce())) { - spdlog::trace("[pong] Received pong from [{}], nonce: {}, latency: {}ms", - peer.authority(), msg.nonce(), peer.ping_latency_ms()); - } else { - spdlog::trace("[pong] Received unexpected pong from [{}], nonce: {}", - peer.authority(), msg.nonce()); - } + // Just acknowledge receipt - could verify nonce if we tracked sent pings + spdlog::trace("[pong] Received pong from [{}], nonce: {}", peer.authority(), msg.nonce()); co_return message_result::handled; } diff --git a/src/network/src/hosts.cpp b/src/network/src/hosts.cpp index d967df13..b3c89166 100644 --- a/src/network/src/hosts.cpp +++ b/src/network/src/hosts.cpp @@ -32,7 +32,7 @@ inline bool is_ipv4_mapped(infrastructure::message::ip_address const& ip) { } // anonymous namespace hosts::hosts(settings const& settings) - : capacity_(std::min(max_address, size_t(settings.host_pool_capacity))) + : capacity_(std::min(max_address, static_cast(settings.host_pool_capacity))) , disabled_(capacity_ == 0) , file_path_(settings.hosts_file) , addresses_(capacity_ > 0 ? capacity_ : 1) @@ -114,7 +114,7 @@ code hosts::fetch(address& out) const { addresses_.cvisit_all([&](address const& addr) { if (found) return; - if (current == size_t(random_index)) { + if (current == static_cast(random_index)) { out = addr; found = true; } diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp index 58fe3964..1bda321b 100644 --- a/src/network/src/p2p_node.cpp +++ b/src/network/src/p2p_node.cpp @@ -21,27 +21,22 @@ using namespace std::chrono_literals; p2p_node::p2p_node(settings const& settings) : settings_(settings) - , pool_(thread_ceiling(settings.threads)) // 0 means use all cores + , pool_(settings.threads > 0 ? settings.threads : 1) , manager_(pool_.get_executor()) , hosts_(settings) - , banlist_(settings.banlist_file) , top_block_({null_hash, 0}) - , new_peer_channel_(std::make_unique>(pool_.get_executor(), 100)) - , stop_signal_(std::make_unique(pool_.get_executor(), 1)) { - spdlog::debug("[p2p_node] p2p_node constructor - thread pool size: {}", pool_.size()); + spdlog::debug("[p2p_node] p2p_node constructor - member init complete"); // Register default message handlers using typed registration // The make_handler<> wrapper handles parsing automatically dispatcher_.register_handler(handlers::ping::handle); dispatcher_.register_handler(handlers::pong::handle); + spdlog::debug("[p2p_node] p2p_node constructor completed successfully"); } p2p_node::~p2p_node() { - spdlog::debug("[p2p_node] destructor starting"); stop(); - spdlog::debug("[p2p_node] destructor - stop() done, calling join()..."); join(); - spdlog::debug("[p2p_node] destructor done"); } ::asio::awaitable p2p_node::start() { @@ -51,14 +46,8 @@ ::asio::awaitable p2p_node::start() { stopped_ = false; - // Load banlist from file (persisted bans survive restarts) - if (!banlist_.load()) { - spdlog::warn("[p2p_node] Failed to load banlist from file"); - } - // hosts_ loads from file in constructor - spdlog::info("[p2p_node] Loaded {} host addresses, {} banned IPs", - hosts_.count(), banlist_.size()); + spdlog::info("[p2p_node] Loaded {} host addresses", hosts_.count()); // Seed if needed if (hosts_.count() < settings_.host_pool_capacity / 2) { @@ -70,63 +59,25 @@ ::asio::awaitable p2p_node::start() { } ::asio::awaitable p2p_node::run() { - spdlog::debug("[p2p_node] run() starting"); - if (stopped_) { - spdlog::debug("[p2p_node] run() - already stopped"); co_return error::service_stopped; } - // Run all network tasks in parallel using task_group on pool_ executor. - // We use task_group instead of && operator because && runs all coroutines - // on the caller's executor (which may be single-threaded). task_group - // uses pool_.get_executor() which has multiple threads, allowing true - // parallelism and proper coroutine scheduling. - task_group network_tasks(pool_.get_executor()); - - spdlog::debug("[p2p_node] Spawning peer_supervisor..."); - network_tasks.spawn([this]() -> ::asio::awaitable { - spdlog::debug("[p2p_node] peer_supervisor coroutine starting"); - co_await peer_supervisor(); - spdlog::debug("[p2p_node] peer_supervisor coroutine finished"); - }); - - spdlog::debug("[p2p_node] Spawning run_inbound..."); - network_tasks.spawn([this]() -> ::asio::awaitable { - spdlog::debug("[p2p_node] run_inbound coroutine starting"); - co_await run_inbound(); - spdlog::debug("[p2p_node] run_inbound coroutine finished"); - }); - - spdlog::debug("[p2p_node] Spawning run_outbound..."); - network_tasks.spawn([this]() -> ::asio::awaitable { - spdlog::debug("[p2p_node] run_outbound coroutine starting"); - co_await run_outbound(); - spdlog::debug("[p2p_node] run_outbound coroutine finished"); - }); - - // Wait for supervisor to be ready before connecting manual peers - while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { - co_await ::asio::post(pool_.get_executor(), ::asio::use_awaitable); - } + // Start inbound acceptor + ::asio::co_spawn(pool_.get_executor(), run_inbound(), ::asio::detached); - // Connect to configured manual peers (supervisor is now ready) - if (!settings_.peers.empty()) { - spdlog::debug("[p2p_node] run() - connecting to {} manual peers", settings_.peers.size()); - for (auto const& peer : settings_.peers) { - auto result = co_await connect(peer.host(), peer.port()); - if (!result) { - spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", - peer.host(), peer.port(), result.error().message()); - } + // Start outbound connection manager + ::asio::co_spawn(pool_.get_executor(), run_outbound(), ::asio::detached); + + // Connect to configured manual peers + for (auto const& peer : settings_.peers) { + auto result = co_await connect(peer.host(), peer.port()); + if (!result) { + spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", + peer.host(), peer.port(), result.error().message()); } } - spdlog::debug("[p2p_node] All tasks spawned, waiting on join..."); - // Wait for all tasks to complete (i.e., until stop() is called) - co_await network_tasks.join(); - spdlog::debug("[p2p_node] All tasks completed"); - co_return error::success; } @@ -136,41 +87,20 @@ void p2p_node::stop() { } stopped_ = true; - supervisor_ready_ = false; // Reset for potential restart - // Close stop_signal_ channel - this wakes up ALL waiters (peer_supervisor, - // maintain_outbound_connections) because async_receive returns error when closed - if (stop_signal_) { - stop_signal_->close(); - } - - // Close the new peer channel to wake up peer_supervisor - if (new_peer_channel_) { - new_peer_channel_->close(); - } - - // Stop acceptor - this causes run_inbound() to exit + // Stop acceptor if (acceptor_) { std::error_code ec; acceptor_->close(ec); } - // Stop all peers - this causes peer->run() to exit, which allows - // peer_supervisor's peer_tasks.join() to complete + // Stop all peers manager_.stop_all(); - // Save banlist to file (final save before shutdown) - banlist_.save(); - // hosts_ saves to file in destructor - // NOTE: We do NOT call pool_.stop() here! - // With structured concurrency, all coroutines will complete naturally: - // 1. run_inbound() exits (acceptor closed) - // 2. run_outbound() exits (stopped_ = true) - // 3. peer_supervisor() exits after peer_tasks.join() completes - // 4. run() returns, then join() can complete - // Calling pool_.stop() here would abort pending work and prevent clean shutdown. + // Stop thread pool + pool_.stop(); } void p2p_node::join() { @@ -321,37 +251,36 @@ awaitable_expected p2p_node::connect( co_return std::unexpected(error::address_blocked); } - // Create response channel for handshake result - auto response_channel = std::make_shared(executor, 1); - - // Send peer to supervisor for FULL lifecycle management (structured concurrency) - // The supervisor will do: peer->run() && (handshake && protocols) - // This eliminates the need for detached coroutines entirely! - if (new_peer_channel_ && new_peer_channel_->is_open()) { - co_await new_peer_channel_->async_send( - std::error_code{}, - peer_event{peer, peer_direction::outbound, response_channel}, - ::asio::use_awaitable); - } else { + // Start the session's message pump + ::asio::co_spawn(executor, peer->run(), ::asio::detached); + + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { peer->stop(); - co_return std::unexpected(error::service_stopped); + spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", + host, port, handshake_result.error().message()); + co_return std::unexpected(handshake_result.error()); } - // Wait for supervisor to complete handshake and send result - auto [recv_ec, response] = co_await response_channel->async_receive( - ::asio::as_tuple(::asio::use_awaitable)); + spdlog::info("[p2p_node] Handshake complete with {}:{}, version {}, {}", + host, port, handshake_result->negotiated_version, + handshake_result->peer_version->user_agent()); - if (recv_ec || response.result != error::success) { - // Handshake failed - peer is already stopped by supervisor - auto err = recv_ec ? error::channel_stopped : response.result; - spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", - host, port, err.message()); - co_return std::unexpected(err); + // Add to peer manager + auto ec = co_await manager_.add(peer); + if (ec != error::success) { + peer->stop(); + co_return std::unexpected(ec); } - spdlog::info("[p2p_node] Connection complete with {}:{}, version {}, {}", - host, port, peer->negotiated_version(), - peer->peer_version()->user_agent()); + // Start protocol handlers + ::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); co_return peer; } @@ -396,47 +325,57 @@ std::vector p2p_node::get_peers() const { ::asio::awaitable p2p_node::run_seeding() { spdlog::info("[p2p_node] Starting seeding from {} seeds", settings_.seeds.size()); + spdlog::debug("[p2p_node] run_seeding: before seeds check"); if (settings_.seeds.empty()) { spdlog::info("[p2p_node] No seeds configured"); co_return; } - // Use pool's executor for parallel DNS resolution, not this_coro::executor - // (which might be a single-threaded io_context from the caller) - auto executor = pool_.get_executor(); + spdlog::debug("[p2p_node] run_seeding: getting executor"); + auto executor = co_await ::asio::this_coro::executor; + spdlog::debug("[p2p_node] run_seeding: got executor"); + + // Track seeds completed + auto seeds_completed = std::make_shared>(0); + auto const total_seeds = settings_.seeds.size(); + spdlog::debug("[p2p_node] run_seeding: total_seeds = {}", total_seeds); // Copy seeds to avoid reference issues in coroutines + spdlog::debug("[p2p_node] run_seeding: copying seeds"); std::vector seeds_copy( settings_.seeds.begin(), settings_.seeds.end()); + spdlog::debug("[p2p_node] run_seeding: seeds copied, count = {}", seeds_copy.size()); - // Use task_group for structured concurrency - no detached! - task_group seed_tasks(executor); + // Launch seed connections in parallel + for (size_t i = 0; i < seeds_copy.size(); ++i) { + if (stopped_) break; - // Track seeds completed for early exit - auto seeds_completed = std::make_shared>(0); - auto const total_seeds = seeds_copy.size(); + auto const& seed = seeds_copy[i]; + spdlog::debug("[p2p_node] run_seeding: processing seed {} of {}", i + 1, seeds_copy.size()); - // Launch all seed connections in parallel - for (auto const& seed : seeds_copy) { - if (stopped_) break; + auto seed_host = seed.host(); + auto seed_port = seed.port(); + spdlog::debug("[p2p_node] run_seeding: seed {}:{}", seed_host, seed_port); - seed_tasks.spawn([this, host = seed.host(), port = seed.port(), seeds_completed]() -> ::asio::awaitable { - co_await connect_to_seed(host, port, seeds_completed); - }); + // Use member function instead of lambda to avoid capture lifetime issues + spdlog::debug("[p2p_node] run_seeding: about to co_spawn connect_to_seed for {}:{}", seed_host, seed_port); + ::asio::co_spawn(executor, + connect_to_seed(std::move(seed_host), seed_port, seeds_completed), + ::asio::detached); + spdlog::debug("[p2p_node] run_seeding: co_spawned connect_to_seed"); } - spdlog::debug("[p2p_node] run_seeding: {} seed tasks spawned", seeds_copy.size()); + spdlog::debug("[p2p_node] run_seeding: all seed tasks spawned, entering wait loop"); - // Wait for seeds with early exit conditions - // We use a timer loop to check for early exit while tasks run - ::asio::steady_timer check_timer(executor); + // Wait for seeds with simple timeout auto const max_wait = std::chrono::seconds(settings_.connect_timeout_seconds + 35); auto const start_time = std::chrono::steady_clock::now(); - while (seed_tasks.has_active_tasks() && !stopped_) { + while (*seeds_completed < total_seeds && !stopped_) { // Check elapsed time - if (std::chrono::steady_clock::now() - start_time >= max_wait) { + auto elapsed = std::chrono::steady_clock::now() - start_time; + if (elapsed >= max_wait) { spdlog::debug("[p2p_node] Seeding timeout reached"); break; } @@ -448,13 +387,11 @@ ::asio::awaitable p2p_node::run_seeding() { } // Wait a bit before checking again + ::asio::steady_timer check_timer(executor); check_timer.expires_after(1s); co_await check_timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); } - // Wait for remaining tasks to complete (structured concurrency) - co_await seed_tasks.join(); - spdlog::info("[p2p_node] Seeding complete, {} addresses available", hosts_.count()); } @@ -465,8 +402,7 @@ ::asio::awaitable p2p_node::connect_to_seed( { spdlog::debug("[p2p_node] connect_to_seed: starting for {}:{}", seed_host, seed_port); - // Use pool's executor explicitly for parallel operations - auto executor = pool_.get_executor(); + auto executor = co_await ::asio::this_coro::executor; try { auto result = co_await async_connect( @@ -486,77 +422,75 @@ ::asio::awaitable p2p_node::connect_to_seed( spdlog::debug("[p2p_node] connect_to_seed: connected to {}:{}", seed_host, seed_port); auto peer = *result; - // Run the seeding protocol using structured concurrency: - // peer->run() && seeding_protocol() - // This eliminates the need for detached coroutines! - co_await ( - peer->run() && - [&]() -> ::asio::awaitable { - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - - // Perform handshake (uses channels - run() is running in parallel!) - spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { - spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", - seed_host, seed_port, handshake_result.error().message()); - peer->stop(); - co_return; - } + // Start the session's message pump + spdlog::debug("[p2p_node] connect_to_seed: spawning peer->run() for {}:{}", seed_host, seed_port); + ::asio::co_spawn(executor, peer->run(), ::asio::detached); - spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); - // Send getaddr request - auto ec = co_await peer->send(domain::message::get_address{}); - if (ec != error::success) { - peer->stop(); - co_return; - } + // Perform handshake + spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); - // Wait for addr response with timeout - ::asio::steady_timer timer(executor); - timer.expires_after(30s); - bool got_addresses = false; + if (!handshake_result) { + peer->stop(); + spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", + seed_host, seed_port, handshake_result.error().message()); + ++(*seeds_completed); + co_return; + } - while (!got_addresses && !peer->stopped()) { - auto msg_result = co_await ( - peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || - timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) - ); + spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); - if (msg_result.index() == 1) { - // Timeout - break; - } + // Send getaddr request + auto ec = co_await peer->send(domain::message::get_address{}); + if (ec != error::success) { + peer->stop(); + ++(*seeds_completed); + co_return; + } - auto& [recv_ec, raw] = std::get<0>(msg_result); - if (recv_ec) { - break; - } + // Wait for addr response with timeout + ::asio::steady_timer timer(executor); + timer.expires_after(30s); + bool got_addresses = false; - if (raw.heading.command() == domain::message::address::command) { - byte_reader reader(raw.payload); - auto addr_result = domain::message::address::from_data( - reader, peer->negotiated_version()); - if (addr_result) { - auto const count = addr_result->addresses().size(); - spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", - count, seed_host, seed_port); - - for (auto const& addr : addr_result->addresses()) { - hosts_.store(addr); - } - got_addresses = true; - } + while (!got_addresses && !peer->stopped()) { + auto msg_result = co_await ( + peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (msg_result.index() == 1) { + // Timeout + break; + } + + auto& [recv_ec, raw] = std::get<0>(msg_result); + if (recv_ec) { + break; + } + + if (raw.heading.command() == domain::message::address::command) { + byte_reader reader(raw.payload); + auto addr_result = domain::message::address::from_data( + reader, peer->negotiated_version()); + if (addr_result) { + auto const count = addr_result->addresses().size(); + spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", + count, seed_host, seed_port); + + for (auto const& addr : addr_result->addresses()) { + hosts_.store(addr); } + got_addresses = true; } + } + } - peer->stop(); - }() - ); + peer->stop(); } catch (std::exception const& e) { spdlog::debug("[p2p_node] Seed {} exception: {}", seed_host, e.what()); } @@ -585,11 +519,6 @@ ::asio::awaitable p2p_node::run_inbound() { acceptor_ = std::make_unique<::asio::ip::tcp::acceptor>(std::move(*listen_result)); - // Wait for peer_supervisor to be ready (deterministic synchronization) - while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { - co_await ::asio::post(executor, ::asio::use_awaitable); - } - spdlog::info("[p2p_node] Listening on port {}", settings_.inbound_port); // Accept loop @@ -607,25 +536,47 @@ ::asio::awaitable p2p_node::run_inbound() { auto peer = *result; - // Check banlist before proceeding - if (banlist_.is_banned(peer->authority())) { - spdlog::debug("[p2p_node] Rejecting inbound connection from banned peer {}", - peer->authority()); - peer->stop(); - continue; - } + // Handle the new connection in a separate coroutine + ::asio::co_spawn(executor, [this, peer, executor]() -> ::asio::awaitable { + // Check banlist before proceeding + if (banlist_.is_banned(peer->authority())) { + spdlog::debug("[p2p_node] Rejecting inbound connection from banned peer {}", + peer->authority()); + peer->stop(); + co_return; + } - // Send peer to supervisor for FULL lifecycle management (structured concurrency) - // Supervisor will do: peer->run() && (handshake && add_to_manager && protocols) - // No response channel needed for inbound - we don't wait for handshake result - if (new_peer_channel_ && new_peer_channel_->is_open()) { - co_await new_peer_channel_->async_send( - std::error_code{}, - peer_event{peer, peer_direction::inbound, nullptr}, - ::asio::use_awaitable); - } else { - peer->stop(); - } + // Start the session's message pump + ::asio::co_spawn(executor, peer->run(), ::asio::detached); + + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + peer->stop(); + spdlog::debug("[p2p_node] Inbound handshake failed: {}", + handshake_result.error().message()); + co_return; + } + + spdlog::info("[p2p_node] Inbound handshake complete from {}, version {}, {}", + peer->authority(), handshake_result->negotiated_version, + handshake_result->peer_version->user_agent()); + + // Add to peer manager + auto ec = co_await manager_.add(peer); + if (ec != error::success) { + peer->stop(); + co_return; + } + + // Start protocol handlers + co_await run_peer_protocols(peer); + }, ::asio::detached); } } @@ -664,7 +615,6 @@ ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { spdlog::debug("[p2p_node] Failed to send ping to [{}]", peer->authority()); break; } - peer->record_ping_sent(nonce); spdlog::trace("[p2p_node] Sent ping to [{}]", peer->authority()); } continue; @@ -713,52 +663,31 @@ ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { // Cleanup spdlog::debug("[p2p_node] Ending protocols for peer [{}]", peer->authority()); - spdlog::debug("[p2p_node] Calling peer->stop() for [{}]", peer->authority()); peer->stop(); - spdlog::debug("[p2p_node] Calling manager_.remove() for [{}]", peer->authority()); co_await manager_.remove(peer); - spdlog::debug("[p2p_node] manager_.remove() completed for [{}]", peer->authority()); } ::asio::awaitable p2p_node::maintain_outbound_connections() { auto executor = co_await ::asio::this_coro::executor; ::asio::steady_timer timer(executor); - // Wait for peer_supervisor to be ready (deterministic synchronization) - // The && operator starts coroutines but doesn't guarantee execution order. - while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { - // Yield to allow peer_supervisor to start - co_await ::asio::post(executor, ::asio::use_awaitable); - } - - spdlog::info("[p2p_node] maintain_outbound_connections started, target: {} peers", settings_.outbound_connections); - // Maximum number of parallel connection attempts constexpr size_t max_parallel_attempts = 8; while (!stopped_) { auto const current_count = manager_.count_snapshot(); auto const target = settings_.outbound_connections; - auto const host_count = hosts_.count(); - auto const ban_count = banlist_.size(); if (current_count < target) { // Need more connections auto const needed = target - current_count; - spdlog::debug("[p2p_node] Connections: {}/{}, hosts: {}, banned: {}", - current_count, target, host_count, ban_count); - // Always try max_parallel_attempts to find working peers faster // Many addresses may be stale, so cast a wide net auto const batch_size = max_parallel_attempts; std::vector addresses; addresses.reserve(batch_size); - size_t skipped_banned = 0; - size_t skipped_connected = 0; - size_t skipped_pending = 0; - // Fetch addresses, filtering out duplicates and already-connected IPs for (size_t attempts = 0; attempts < batch_size * 3 && addresses.size() < batch_size && !stopped_; ++attempts) { domain::message::network_address addr; @@ -772,19 +701,16 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { // Skip if already pending connection to this IP if (pending_connections_.contains(ip)) { - ++skipped_pending; continue; } // Skip if already connected to this IP if (co_await manager_.exists_by_ip(ip)) { - ++skipped_connected; continue; } // Skip if banned if (banlist_.is_banned(ip)) { - ++skipped_banned; continue; } @@ -804,20 +730,13 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { } if (addresses.empty()) { - spdlog::warn("[p2p_node] No addresses available (hosts: {}, banned: {}, skipped: {} banned, {} connected, {} pending)", - host_count, ban_count, skipped_banned, skipped_connected, skipped_pending); - - // Re-seed if host pool is too low - if (host_count < settings_.host_pool_capacity / 4) { - spdlog::info("[p2p_node] Host pool low ({}), triggering re-seed...", host_count); - co_await run_seeding(); - } + spdlog::debug("[p2p_node] No addresses available for outbound"); } else { spdlog::debug("[p2p_node] Attempting {} parallel connections (need {}, have {})", addresses.size(), needed, current_count); - // Use task_group for structured concurrency - no detached! - task_group connection_tasks(executor); + // Track successful connections with a shared atomic counter + auto success_count = std::make_shared>(0); for (auto const& addr : addresses) { auto const authority = infrastructure::config::authority(addr); @@ -826,7 +745,7 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { // Add to pending connections before spawning pending_connections_.insert(ip); - connection_tasks.spawn([this, addr, ip]() -> ::asio::awaitable { + auto task = [this, addr, ip, success_count]() -> ::asio::awaitable { auto const authority = infrastructure::config::authority(addr); spdlog::trace("[p2p_node] Attempting connection to {}", authority); @@ -841,185 +760,30 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { hosts_.remove(addr); } else { spdlog::debug("[p2p_node] Connected to {}", authority); + ++(*success_count); } - }); + }; + + // Spawn each connection attempt + ::asio::co_spawn(executor, task(), ::asio::detached); } - // Wait for ALL connection attempts to complete (structured concurrency!) - co_await connection_tasks.join(); + // Give connection attempts time to complete + // Use a shorter wait since they're running in parallel + timer.expires_after(std::chrono::seconds(settings_.connect_timeout_seconds + 2)); + co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); // Continue loop to check if we need more connections continue; } } - // Wait before next check - // Use shorter interval when we're below target to recover faster from bans - // Keep wait_time short to allow quick shutdown response - auto const wait_time = (current_count < target) - ? std::chrono::milliseconds(500) // Fast retry when below target - : std::chrono::seconds(5); // Normal check when at target - - // Log status periodically when at target - if (current_count >= target) { - spdlog::debug("[p2p_node] Connections at target: {}/{}, hosts: {}, banned: {}", - current_count, target, host_count, ban_count); - } - - timer.expires_after(wait_time); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - break; // Timer cancelled (shutdown) - } + // Wait before next check when we have enough connections + timer.expires_after(std::chrono::seconds(30)); + co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); } } -// ============================================================================= -// Peer Supervisor (Structured Concurrency) -// ============================================================================= -// -// The peer_supervisor manages all peer lifecycles using the nursery pattern. -// Instead of spawning detached coroutines for each peer, all peer tasks are -// tracked in a task_group and properly awaited on shutdown. -// -// Flow: -// 1. run_inbound() and connect() send peer_events to new_peer_channel_ -// 2. peer_supervisor receives events and spawns peer tasks into task_group -// 3. On stop(), stop_signal_ is triggered -// 4. peer_supervisor stops accepting new peers and waits for all tasks to complete -// -// ============================================================================= - -::asio::awaitable p2p_node::peer_supervisor() { - spdlog::debug("[p2p_node] peer_supervisor started"); - - task_group peer_tasks(pool_.get_executor()); - - // Track ALL spawned peers (including those not yet in manager) - // This is needed for clean shutdown - manager_.stop_all() only stops - // peers that completed handshake, but we need to stop ALL peers. - std::vector all_spawned_peers; - - // Signal that we're ready to receive peers (deterministic synchronization) - supervisor_ready_.store(true, std::memory_order_release); - - while (!stopped_) { - // Wait for new peer event - // NOTE: We don't use || with stop_signal_ because the || operator in asio - // waits for BOTH operations to complete, not just the first one. - // Instead, stop() closes new_peer_channel_ which causes async_receive to return error. - auto [ec, event] = co_await new_peer_channel_->async_receive( - ::asio::as_tuple(::asio::use_awaitable)); - - if (ec) { - // Channel closed (stop() was called) or error - exit - spdlog::debug("[p2p_node] peer_supervisor channel closed: {}", ec.message()); - break; - } - - auto peer = event.peer; - auto direction = event.direction; - auto response_channel = event.response_channel; - - // Track this peer for shutdown - all_spawned_peers.push_back(peer); - - spdlog::debug("[p2p_node] peer_supervisor received {} peer [{}]", - direction == peer_direction::inbound ? "inbound" : "outbound", - peer->authority()); - - // Spawn FULL peer lifecycle into the task group (tracked, not detached!) - // This runs: peer->run() && (handshake && add_to_manager && protocols) - // The && operator ensures both branches run in parallel and we wait for both. - // When peer disconnects, both exit and && completes. - peer_tasks.spawn([this, peer, direction, response_channel]() -> ::asio::awaitable { - try { - co_await ( - peer->run() && - [&]() -> ::asio::awaitable { - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - - // Perform handshake (uses channels - run() is already running!) - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { - spdlog::debug("[p2p_node] Handshake failed for [{}]: {}", - peer->authority(), handshake_result.error().message()); - // Send failure response if caller is waiting - if (response_channel) { - response_channel->try_send(std::error_code{}, handshake_response{handshake_result.error()}); - } - peer->stop(); - co_return; - } - - // Add to peer manager - auto add_ec = co_await manager_.add(peer); - if (add_ec != error::success) { - spdlog::debug("[p2p_node] Failed to add peer [{}] to manager: {}", - peer->authority(), add_ec.message()); - if (response_channel) { - response_channel->try_send(std::error_code{}, handshake_response{add_ec}); - } - peer->stop(); - co_return; - } - - // Send initial ping to get latency data - { - uint64_t ping_nonce = 0; - pseudo_random::fill(reinterpret_cast(&ping_nonce), sizeof(ping_nonce)); - domain::message::ping ping_msg(ping_nonce); - auto ec = co_await peer->send(ping_msg); - if (ec == error::success) { - peer->record_ping_sent(ping_nonce); - } - } - - // Send success response to caller - if (response_channel) { - response_channel->try_send(std::error_code{}, handshake_response{error::success}); - } - - // Run protocols until peer disconnects - co_await run_peer_protocols(peer); - }() - ); - } catch (std::exception const& e) { - spdlog::debug("[p2p_node] Peer [{}] task exception: {}", - peer->authority(), e.what()); - // Send error response if caller is still waiting - if (response_channel) { - response_channel->try_send(std::error_code{}, handshake_response{error::operation_failed}); - } - } - - spdlog::debug("[p2p_node] Peer [{}] full lifecycle completed", peer->authority()); - }); - } - - spdlog::debug("[p2p_node] peer_supervisor stopping {} spawned peers before join", - all_spawned_peers.size()); - - // Stop ALL spawned peers (including those not yet in manager) - // This ensures peers still in handshake phase are also stopped, - // allowing their run() to exit and peer_tasks.join() to complete. - for (auto& peer : all_spawned_peers) { - peer->stop(); - } - - spdlog::debug("[p2p_node] peer_supervisor waiting for {} active peer tasks", - peer_tasks.active_count()); - - // CRITICAL: Wait for all peer tasks to complete - // This is the structured concurrency guarantee - no orphaned tasks! - co_await peer_tasks.join(); - - spdlog::debug("[p2p_node] peer_supervisor finished - all peer tasks completed"); -} - uint64_t p2p_node::generate_nonce() { uint64_t nonce = 0; pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); diff --git a/src/network/src/peer_manager.cpp b/src/network/src/peer_manager.cpp index d51aee49..6d40245e 100644 --- a/src/network/src/peer_manager.cpp +++ b/src/network/src/peer_manager.cpp @@ -92,48 +92,29 @@ ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { co_return; } - spdlog::debug("[peer_manager] remove() called for peer [{}]", peer->authority()); - auto nonce = peer->nonce(); if (nonce == 0) { auto const& auth = peer->authority(); nonce = std::hash{}(auth.to_string()); } - spdlog::debug("[peer_manager] remove() calling remove_by_nonce for peer [{}]", peer->authority()); co_await remove_by_nonce(nonce); - spdlog::debug("[peer_manager] remove() completed for peer [{}]", peer->authority()); } ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { - // Note: With structured concurrency, remove() is called from peer tasks - // that are tracked by task_group. The peer_supervisor waits for all tasks - // to complete before shutdown finishes, so this operation is safe. - // We don't check stopped() because we want cleanup to proceed normally. - - spdlog::debug("[peer_manager] remove_by_nonce() starting co_spawn on strand for nonce {}", nonce); - co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { - spdlog::debug("[peer_manager] remove_by_nonce() inside strand lambda for nonce {}", nonce); auto it = peers_.find(nonce); if (it != peers_.end()) { spdlog::debug("[peer_manager] Removed peer [{}], remaining: {}", it->second->authority(), peers_.size() - 1); peers_.erase(it); count_.store(peers_.size()); - } else { - spdlog::debug("[peer_manager] Peer with nonce {} not found in map", nonce); } co_return; }, ::asio::use_awaitable); - - spdlog::debug("[peer_manager] remove_by_nonce() co_spawn completed for nonce {}", nonce); } ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { - if (stopped()) { - co_return false; - } co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { co_return peers_.find(nonce) != peers_.end(); }, ::asio::use_awaitable); @@ -142,9 +123,6 @@ ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { ::asio::awaitable peer_manager::exists_by_authority( infrastructure::config::authority const& authority) const { - if (stopped()) { - co_return false; - } co_return co_await ::asio::co_spawn(strand_, [this, &authority]() -> ::asio::awaitable { for (auto const& [nonce, peer] : peers_) { if (peer->authority() == authority) { @@ -156,9 +134,6 @@ ::asio::awaitable peer_manager::exists_by_authority( } ::asio::awaitable peer_manager::exists_by_ip(::asio::ip::address const& ip) const { - if (stopped()) { - co_return false; - } co_return co_await ::asio::co_spawn(strand_, [this, &ip]() -> ::asio::awaitable { for (auto const& [nonce, peer] : peers_) { if (peer->authority().asio_ip() == ip) { @@ -170,9 +145,6 @@ ::asio::awaitable peer_manager::exists_by_ip(::asio::ip::address const& ip } ::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) const { - if (stopped()) { - co_return nullptr; - } co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { auto it = peers_.find(nonce); if (it != peers_.end()) { @@ -183,9 +155,6 @@ ::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) } ::asio::awaitable> peer_manager::all() const { - if (stopped()) { - co_return std::vector{}; - } co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable> { std::vector result; result.reserve(peers_.size()); @@ -197,9 +166,6 @@ ::asio::awaitable> peer_manager::all() const { } ::asio::awaitable peer_manager::count() const { - if (stopped()) { - co_return 0; - } co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable { co_return peers_.size(); }, ::asio::use_awaitable); @@ -233,9 +199,8 @@ void peer_manager::stop_all() { spdlog::debug("[peer_manager] Stopping all peers"); - // Post to strand to safely stop all peers and clear the map. - // Note: With structured concurrency, peer tasks may still call remove() after - // this, but remove() handles "not found" gracefully (just does nothing). + // Post to strand to safely iterate and clean up + // Note: Callers should run the io_context to ensure completion ::asio::post(strand_, [this]() { for (auto& [nonce, peer] : peers_) { peer->stop(); diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp index db55e1ca..f5095591 100644 --- a/src/network/src/peer_session.cpp +++ b/src/network/src/peer_session.cpp @@ -31,7 +31,6 @@ boost::unordered_flat_map const known_client {"Knuth:", "KTH"}, {"Bitcoin ABC:", "ABC"}, {"BitcoinUnlimited:", "BU"}, - {"BCH Unlimited:", "BU"}, {"BUCash:", "BU"}, }; @@ -151,8 +150,6 @@ void peer_session::stop(code const& ec) { // Close channels outbound_.close(); inbound_.close(); - headers_responses_.close(); - block_responses_.close(); // Shutdown socket boost_code ignore; @@ -321,51 +318,6 @@ bool peer_session::is_preferred_download() const { && !is_client(); } -// ============================================================================= -// Statistics (lock-free, benign data races acceptable) -// ============================================================================= - -size_t peer_session::bytes_received() const { - return bytes_received_.load(std::memory_order_relaxed); -} - -size_t peer_session::bytes_sent() const { - return bytes_sent_.load(std::memory_order_relaxed); -} - -uint32_t peer_session::ping_latency_ms() const { - return ping_latency_ms_.load(std::memory_order_relaxed); -} - -void peer_session::record_ping_sent(uint64_t nonce) { - // Store time as nanoseconds since steady_clock epoch for lock-free access - auto const now = std::chrono::steady_clock::now(); - auto const ns = std::chrono::duration_cast( - now.time_since_epoch()).count(); - pending_ping_time_ns_.store(ns, std::memory_order_relaxed); - pending_ping_nonce_.store(nonce, std::memory_order_relaxed); -} - -bool peer_session::record_pong_received(uint64_t nonce) { - auto const expected_nonce = pending_ping_nonce_.load(std::memory_order_relaxed); - if (expected_nonce == 0 || nonce != expected_nonce) { - return false; - } - - auto const sent_ns = pending_ping_time_ns_.load(std::memory_order_relaxed); - auto const now = std::chrono::steady_clock::now(); - auto const now_ns = std::chrono::duration_cast( - now.time_since_epoch()).count(); - auto const latency_ms = static_cast((now_ns - sent_ns) / 1'000'000); - ping_latency_ms_.store(latency_ms, std::memory_order_relaxed); - pending_ping_nonce_.store(0, std::memory_order_relaxed); - return true; -} - -std::chrono::steady_clock::time_point peer_session::connection_time() const { - return connection_time_; -} - // ============================================================================= // Internal Coroutines // ============================================================================= @@ -422,9 +374,6 @@ ::asio::awaitable peer_session::write_loop() { co_return; } - // Track bytes sent - bytes_sent_.fetch_add(bytes_written, std::memory_order_relaxed); - spdlog::trace("[peer_session] Sent {} bytes to [{}]", bytes_written, authority()); } } @@ -530,24 +479,12 @@ awaitable_expected peer_session::read_message() { co_return std::unexpected(error::bad_stream); } - // Track bytes received (header + payload) - bytes_received_.fetch_add(heading::maximum_size() + head.payload_size(), std::memory_order_relaxed); - spdlog::debug("[peer_session] Received {} from [{}] ({} bytes)", head.command(), authority_with_agent(), head.payload_size()); co_return raw_message{head, std::move(payload)}; } -// ============================================================================= -// Direct I/O (for handshake before run() starts) -// ============================================================================= - -awaitable_expected peer_session::read_message_direct() { - // Just delegate to the private read_message() implementation - return read_message(); -} - void peer_session::signal_activity() { activity_signaled_ = true; // Cancel and restart the inactivity timer @@ -567,108 +504,38 @@ awaitable_expected async_connect( { using namespace ::asio::experimental::awaitable_operators; - // Try to parse hostname as IP address first (skip DNS for IPs) - std::error_code ip_parse_ec; - auto ip_address = ::asio::ip::make_address(hostname, ip_parse_ec); - - ::asio::ip::tcp::endpoint direct_endpoint; - bool is_ip_address = !ip_parse_ec; - - if (is_ip_address) { - // Hostname is already an IP address, skip DNS resolution - direct_endpoint = ::asio::ip::tcp::endpoint(ip_address, port); - spdlog::debug("[async_connect] {} is an IP address, skipping DNS", hostname); - } else { - // Need DNS resolution - auto resolver = std::make_shared<::asio::ip::tcp::resolver>(executor); - - // DNS resolution timeout (5 seconds should be plenty for DNS) - auto dns_timer = std::make_shared<::asio::steady_timer>(executor); - dns_timer->expires_after(std::chrono::seconds(5)); - - auto start_time = std::chrono::steady_clock::now(); - spdlog::debug("[async_connect] Starting DNS resolution for {} with 5s timeout", hostname); - - // Use a channel to get the first result (DNS or timeout) - auto result_channel = std::make_shared, - std::error_code - > - >>(executor, 1); - - // Spawn DNS resolution - ::asio::co_spawn(executor, [resolver, hostname, port, result_channel]() -> ::asio::awaitable { - auto [ec, endpoints] = co_await resolver->async_resolve( - hostname, std::to_string(port), ::asio::as_tuple(::asio::use_awaitable)); - result_channel->try_send(std::error_code{}, - std::variant, std::error_code>{ - std::make_tuple(ec, endpoints)}); - }, ::asio::detached); - - // Spawn timer - ::asio::co_spawn(executor, [dns_timer, result_channel]() -> ::asio::awaitable { - auto [ec] = co_await dns_timer->async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (!ec) { - result_channel->try_send(std::error_code{}, - std::variant, std::error_code>{ - std::make_error_code(std::errc::timed_out)}); - } - }, ::asio::detached); - - // Wait for first result - auto [recv_ec, result] = co_await result_channel->async_receive( - ::asio::as_tuple(::asio::use_awaitable)); - - auto elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start_time).count(); - - // Cancel whichever didn't complete - resolver->cancel(); - dns_timer->cancel(); + // Create resolver + ::asio::ip::tcp::resolver resolver(executor); - if (recv_ec) { - spdlog::debug("[async_connect] DNS channel error for {}: {}", hostname, recv_ec.message()); - co_return std::unexpected(error::resolve_failed); - } - - // Check which result we got - if (result.index() == 1) { - // Timeout - spdlog::debug("[async_connect] DNS resolution for {} timed out after {}ms", hostname, elapsed); - co_return std::unexpected(error::resolve_failed); - } - - auto [resolve_ec, endpoints] = std::get<0>(result); - spdlog::debug("[async_connect] DNS completed for {} in {}ms, ec={}", hostname, elapsed, resolve_ec.message()); - - if (resolve_ec) { - spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); - co_return std::unexpected(error::resolve_failed); - } + // Resolve hostname + auto [resolve_ec, endpoints] = co_await resolver.async_resolve( + hostname, + std::to_string(port), + ::asio::as_tuple(::asio::use_awaitable)); - // Use first resolved endpoint - direct_endpoint = *endpoints.begin(); + if (resolve_ec) { + spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); + co_return std::unexpected(error::resolve_failed); } - // Create socket and timer for connection timeout + // Create socket and timer for timeout ::asio::ip::tcp::socket socket(executor); ::asio::steady_timer timer(executor); timer.expires_after(timeout); - // Race: connect vs timeout (use single endpoint connect) - auto connect_result = co_await ( - socket.async_connect(direct_endpoint, ::asio::as_tuple(::asio::use_awaitable)) || + // Race: connect vs timeout + auto result = co_await ( + ::asio::async_connect(socket, endpoints, ::asio::as_tuple(::asio::use_awaitable)) || timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) ); - if (connect_result.index() == 1) { + if (result.index() == 1) { // Timeout won spdlog::debug("[async_connect] Connection to {}:{} timed out", hostname, port); co_return std::unexpected(error::channel_timeout); } - auto [connect_ec] = std::get<0>(connect_result); + auto [connect_ec, endpoint] = std::get<0>(result); if (connect_ec) { spdlog::debug("[async_connect] Failed to connect to {}:{}: {}", hostname, port, connect_ec.message()); diff --git a/src/network/src/protocols_coro.cpp b/src/network/src/protocols_coro.cpp index c852c14a..1cd5d7b7 100644 --- a/src/network/src/protocols_coro.cpp +++ b/src/network/src/protocols_coro.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include @@ -221,132 +219,6 @@ awaitable_expected perform_handshake( co_return handshake_result{peer_version, negotiated}; } -// ============================================================================= -// Direct Handshake (no message pump required) -// ============================================================================= -// -// This version of handshake reads/writes directly to the socket without -// needing peer->run() to be running. This enables structured concurrency -// by eliminating the need to spawn run() with detached before handshake. -// -// After handshake completes, the peer is sent to peer_supervisor which -// spawns run() + protocols in a tracked task_group. -// -// ============================================================================= - -awaitable_expected perform_handshake_direct( - peer_session& peer, - handshake_config const& config) -{ - auto const& authority = peer.authority(); - - spdlog::debug("[protocol] Starting direct handshake with [{}]", authority); - - // Send our version message (directly to socket) - auto version_msg = make_version_message(config, authority); - auto send_ec = co_await peer.send_direct(version_msg); - if (send_ec != error::success) { - spdlog::debug("[protocol] Failed to send version to [{}]", authority); - co_return std::unexpected(send_ec); - } - - // We need to receive both version and verack from the peer - // The order may vary, so we track what we've received - bool got_version = false; - bool got_verack = false; - domain::message::version::const_ptr peer_version; - - auto deadline = std::chrono::steady_clock::now() + config.timeout; - auto executor = co_await ::asio::this_coro::executor; - - while (!got_version || !got_verack) { - auto remaining = std::chrono::duration_cast( - deadline - std::chrono::steady_clock::now()); - - if (remaining <= 0s) { - spdlog::debug("[protocol] Handshake timeout with [{}]", authority); - co_return std::unexpected(error::channel_timeout); - } - - // Read message directly from socket with timeout - // Use racing pattern with timer - ::asio::steady_timer timer(executor, remaining); - - auto result = co_await ( - peer.read_message_direct() || - timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) - ); - - // Check which completed first - if (result.index() == 1) { - // Timer won - timeout - spdlog::debug("[protocol] Handshake timeout with [{}]", authority); - co_return std::unexpected(error::channel_timeout); - } - - // Message received - auto& msg_result = std::get<0>(result); - if (!msg_result) { - spdlog::debug("[protocol] Failed to receive message from [{}]: {}", - authority, msg_result.error().message()); - co_return std::unexpected(msg_result.error()); - } - - auto const& raw = *msg_result; - auto const& command = raw.heading.command(); - - if (command == domain::message::version::command && !got_version) { - // Parse version message - byte_reader reader(raw.payload); - auto version_result = domain::message::version::from_data(reader, peer.negotiated_version()); - if (!version_result) { - spdlog::debug("[protocol] Failed to parse version from [{}]", authority); - co_return std::unexpected(error::bad_stream); - } - auto version = std::make_shared(std::move(*version_result)); - - spdlog::debug("[protocol] Received version from [{}] protocol ({}) user agent: {}", - authority, version->value(), version->user_agent()); - - // Validate - if (!validate_peer_version(*version, config, authority)) { - co_return std::unexpected(error::channel_stopped); - } - - peer_version = version; - got_version = true; - - // Send verack in response (directly to socket) - auto verack_ec = co_await peer.send_direct(domain::message::verack{}); - if (verack_ec != error::success) { - spdlog::debug("[protocol] Failed to send verack to [{}]", authority); - co_return std::unexpected(verack_ec); - } - } - else if (command == domain::message::verack::command && !got_verack) { - spdlog::debug("[protocol] Received verack from [{}]", authority); - got_verack = true; - } - else { - // Unexpected message during handshake - log but continue - spdlog::debug("[protocol] Unexpected message '{}' during handshake with [{}]", - command, authority); - } - } - - // Calculate negotiated version - auto negotiated = std::min(peer_version->value(), config.protocol_version); - - // Update peer session - peer.set_peer_version(peer_version); - peer.set_negotiated_version(negotiated); - - spdlog::debug("[protocol] Direct handshake complete with [{}], negotiated version {}", - authority, negotiated); - - co_return handshake_result{peer_version, negotiated}; -} - handshake_config make_handshake_config( settings const& network_settings, uint32_t current_height, @@ -670,108 +542,6 @@ awaitable_expected request_block( } } -awaitable_expected> request_blocks_batch( - peer_session& peer, - std::vector> const& blocks, - std::chrono::seconds timeout) -{ - if (blocks.empty()) { - co_return std::vector{}; - } - - // Build hash -> height lookup map - boost::unordered_flat_map expected_blocks; - expected_blocks.reserve(blocks.size()); - - // Build inventory list for getdata - domain::message::inventory_vector::list inventories; - inventories.reserve(blocks.size()); - - for (auto const& [height, hash] : blocks) { - expected_blocks[hash] = height; - inventories.emplace_back(domain::message::inventory_vector::type_id::block, hash); - } - - domain::message::get_data request(std::move(inventories)); - - spdlog::debug("[protocol] Requesting {} blocks in batch from [{}] ({}-{})", - blocks.size(), peer.authority(), - blocks.front().first, blocks.back().first); - - // Send ONE getdata with all block hashes - auto ec = co_await peer.send(request); - if (ec != error::success) { - co_return std::unexpected(ec); - } - - // Receive blocks as they arrive - auto executor = co_await ::asio::this_coro::executor; - auto deadline = std::chrono::steady_clock::now() + timeout; - - std::vector received_blocks; - received_blocks.reserve(blocks.size()); - - while (received_blocks.size() < blocks.size()) { - auto remaining = std::chrono::duration_cast( - deadline - std::chrono::steady_clock::now()); - - if (remaining <= 0s) { - spdlog::debug("[protocol] Timeout waiting for batch blocks from [{}] ({}/{} received)", - peer.authority(), received_blocks.size(), blocks.size()); - co_return std::unexpected(error::channel_timeout); - } - - ::asio::steady_timer timer(executor, remaining); - - auto result = co_await ( - peer.block_responses().async_receive(::asio::as_tuple(::asio::use_awaitable)) || - timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) - ); - - if (result.index() == 1) { - spdlog::debug("[protocol] Timeout waiting for batch blocks from [{}]", peer.authority()); - co_return std::unexpected(error::channel_timeout); - } - - auto& [recv_ec, raw] = std::get<0>(result); - if (recv_ec) { - co_return std::unexpected(error::channel_stopped); - } - - // Parse the block - byte_reader reader(raw.payload); - auto block_result = domain::message::block::from_data(reader, peer.negotiated_version()); - if (!block_result) { - spdlog::debug("[protocol] Failed to parse block from [{}]", peer.authority()); - co_return std::unexpected(error::bad_stream); - } - - // Look up the height for this block - auto const block_hash = block_result->header().hash(); - auto it = expected_blocks.find(block_hash); - if (it == expected_blocks.end()) { - // Not a block we requested - ignore (could be from another request) - spdlog::trace("[protocol] Received unexpected block from [{}], ignoring", - peer.authority()); - continue; - } - - auto height = it->second; - expected_blocks.erase(it); - - received_blocks.push_back({height, std::move(*block_result)}); - } - - // Sort by height for caller convenience - std::sort(received_blocks.begin(), received_blocks.end(), - [](auto const& a, auto const& b) { return a.height < b.height; }); - - spdlog::debug("[protocol] Received {} blocks in batch from [{}]", - received_blocks.size(), peer.authority()); - - co_return received_blocks; -} - // ----------------------------------------------------------------------------- // Inventory Protocol // ----------------------------------------------------------------------------- diff --git a/src/network/src/settings.cpp b/src/network/src/settings.cpp index 0c757f41..ac1ca138 100644 --- a/src/network/src/settings.cpp +++ b/src/network/src/settings.cpp @@ -31,13 +31,12 @@ settings::settings() , connect_batch_size(5) , connect_timeout_seconds(5) , channel_handshake_seconds(6000) - , channel_heartbeat_minutes(2) // BCHN: PING_INTERVAL = 2 minutes + , channel_heartbeat_minutes(5) , channel_inactivity_minutes(10) , channel_expiration_minutes(60) , channel_germination_seconds(30) , host_pool_capacity(1000) , hosts_file("hosts.cache") - , banlist_file("banlist.dat") , self(unspecified_network_address) // , bitcoin_cash(false) @@ -86,9 +85,6 @@ settings::settings(domain::config::network context) seeds.emplace_back("dnsseed.electroncash.de", 8333); // Electroncash.de seeds.emplace_back("bchseed.c3-soft.com", 8333); // C3 Soft (NilacTheGrim) seeds.emplace_back("bch.bitjson.com", 8333); // Jason Dreyzehner - - // // TODO(fernando): TEMPORARY - hardcoded peer for testing - // peers.emplace_back("194.14.247.36", 8333); #else identifier = netmagic::btc_mainnet; seeds.reserve(6); diff --git a/src/node-exe/src/main.cpp b/src/node-exe/src/main.cpp index a9979a17..f5f89ce9 100644 --- a/src/node-exe/src/main.cpp +++ b/src/node-exe/src/main.cpp @@ -2,23 +2,21 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include -#include #include + #include -#include +#include #include +#include #include #include #include +#include #include #include #include -#include - #include "tui_dashboard.hpp" KTH_USE_MAIN @@ -31,70 +29,25 @@ std::string version() { void do_help(kth::node::parser& metadata, std::ostream& output) { auto const options = metadata.load_options(); - kth::infrastructure::config::printer help(options, application_name, "Runs a Bitcoin Cash full-node."); + kth::infrastructure::config::printer help(options, application_name, KTH_INFORMATION_MESSAGE); help.initialize(); help.commandline(output); } void do_settings(kth::node::parser& metadata, std::ostream& output) { auto const settings = metadata.load_settings(); - kth::infrastructure::config::printer print(settings, application_name, "These are the configuration settings that can be set."); + kth::infrastructure::config::printer print(settings, application_name, KTH_SETTINGS_MESSAGE); print.initialize(); print.settings(output); } -// Global signal state for run_with_log -namespace { - std::atomic g_signal_received{0}; - - extern "C" void log_mode_signal_handler(int signal_number) { - // std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); - // std::fflush(stderr); - g_signal_received.store(signal_number); - } -} - bool run_with_log(kth::node::executor& host) { // Traditional log mode - scrolling output - - // Install signal handler IMMEDIATELY so Ctrl-C works during startup - g_signal_received.store(0); - auto prev_sigint = std::signal(SIGINT, log_mode_signal_handler); - auto prev_sigterm = std::signal(SIGTERM, log_mode_signal_handler); - - // Start node (blocks until ready) - auto ec = host.start(); - if (ec != kth::error::success) { - // Restore handlers - std::signal(SIGINT, prev_sigint); - std::signal(SIGTERM, prev_sigterm); - return false; - } - - // Check if signal was received during startup - if (g_signal_received.load() != 0) { - spdlog::info("[node] Signal received during startup, stopping..."); - host.stop(); - std::signal(SIGINT, prev_sigint); - std::signal(SIGTERM, prev_sigterm); - return true; - } - - // Wait for SIGINT/SIGTERM (poll the atomic) - while (g_signal_received.load() == 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - spdlog::info("[node] Stop signal detected (code: {}).", g_signal_received.load()); - - // Stop node (blocks until stopped) - host.stop(); - - // Restore handlers - std::signal(SIGINT, prev_sigint); - std::signal(SIGTERM, prev_sigterm); - - return true; + return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { + if (ec != kth::error::success) { + host.signal_stop(); + } + }); } bool run_with_tui(kth::node::executor& host) { @@ -112,7 +65,7 @@ bool run_with_tui(kth::node::executor& host) { status.version = std::string(kth::version); status.network_name = "BCH Mainnet"; // TODO: get from config status.state = kth::node_exe::node_status::sync_state::starting; - status.start_time = std::chrono::system_clock::now(); + status.start_time = std::chrono::system_clock::now(); // Initialize start time dashboard->update_status(status); // Start TUI @@ -123,33 +76,44 @@ bool run_with_tui(kth::node::executor& host) { return run_with_log(host); // Fallback to log mode } - // Start node (blocks until ready) - auto ec = host.start(); - if (ec != kth::error::success) { + // Run node (non-blocking) + bool init_ok = host.init_run(version(), kth::node::start_modules::all, [&host, &dashboard, &status](std::error_code const& ec) { + if (ec != kth::error::success) { + status.state = kth::node_exe::node_status::sync_state::error; + dashboard->update_status(status); + dashboard->request_exit(); // Signal TUI to exit on error + } + }); + + if (!init_ok) { dashboard->stop(); return false; } - // Update status to syncing headers - status.state = kth::node_exe::node_status::sync_state::syncing_headers; - dashboard->update_status(status); + // TODO(fernando): Update dashboard periodically with node status + // This would be done via a callback mechanism from the node - // Wait for TUI exit (user pressed q or ESC) + // Wait for TUI exit (user pressed q or ESC, or node error) while (dashboard->is_running()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - // Stop TUI first - dashboard->stop(); + // Stop node if TUI exited + if (!host.stopped()) { + host.signal_stop(); + } - // Stop node (blocks until stopped) - host.stop(); - return true; + dashboard->stop(); + return host.close(); } bool run_daemon(kth::node::executor& host) { - // Daemon mode - same as log mode but for systemd - return run_with_log(host); + // Daemon mode - minimal output, suitable for systemd + return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { + if (ec != kth::error::success) { + host.signal_stop(); + } + }); } bool run(kth::node::executor& host, kth::display_mode mode) { diff --git a/src/node-exe/src/tui_dashboard.cpp b/src/node-exe/src/tui_dashboard.cpp index e0c9bec0..72ceab59 100644 --- a/src/node-exe/src/tui_dashboard.cpp +++ b/src/node-exe/src/tui_dashboard.cpp @@ -62,14 +62,13 @@ tui_dashboard::tui_dashboard() { splash_start_ = std::chrono::steady_clock::now(); // Define navigable screens (after splash) - // TODO: Only DASHBOARD and LOGS for now, others coming later navigable_screens_ = { screen_id::dashboard, - // screen_id::network, - // screen_id::blockchain, - // screen_id::mempool, + screen_id::network, + screen_id::blockchain, + screen_id::mempool, screen_id::logs, - // screen_id::terminal, + screen_id::terminal, }; // Initialize terminal with welcome message @@ -243,21 +242,6 @@ void tui_dashboard::update_status(node_status const& status) { } } -void tui_dashboard::add_log(std::string const& message) { - { - std::lock_guard lock(status_mutex_); - status_.recent_logs.push_back(message); - // Keep only last 100 logs - while (status_.recent_logs.size() > 100) { - status_.recent_logs.erase(status_.recent_logs.begin()); - } - } - auto* scr = screen_.load(); - if (scr != nullptr) { - scr->PostEvent(Event::Custom); - } -} - bool tui_dashboard::is_running() const { return running_; } @@ -530,107 +514,7 @@ Element tui_dashboard::render_dashboard() { } Element tui_dashboard::render_network_screen() { - Elements peer_rows; - - // Header row - peer_rows.push_back(hbox({ - text(" ") | size(WIDTH, EQUAL, 2), - text("ADDRESS") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 22), - text("USER AGENT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 16), - text("HEIGHT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), - text("RECV") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), - text("SENT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), - text("PING") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 8), - text("TIME") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 8), - })); - - peer_rows.push_back(separator() | color(colors::dark_gray)); - - if (status_.peers.empty()) { - peer_rows.push_back(text(" No peers connected...") | color(colors::gray) | dim); - } else { - for (auto const& peer : status_.peers) { - // Direction indicator - auto direction = peer.is_inbound ? - text("↓ ") | color(colors::kth_violet) : - text("↑ ") | color(colors::cyan); - - // Ping color based on latency - auto ping_col = peer.ping_ms == 0 ? colors::gray : - peer.ping_ms < 100 ? colors::green : - peer.ping_ms < 300 ? colors::orange : colors::red; - - auto ping_str = peer.ping_ms > 0 ? - std::to_string(peer.ping_ms) + "ms" : "-"; - - // Connected time - auto time_str = format_duration(peer.connected_duration); - // Shorten to just the most significant part - if (peer.connected_duration.count() >= 86400) { - time_str = std::to_string(peer.connected_duration.count() / 86400) + "d"; - } else if (peer.connected_duration.count() >= 3600) { - time_str = std::to_string(peer.connected_duration.count() / 3600) + "h"; - } else if (peer.connected_duration.count() >= 60) { - time_str = std::to_string(peer.connected_duration.count() / 60) + "m"; - } else { - time_str = std::to_string(peer.connected_duration.count()) + "s"; - } - - // User agent - truncate if too long - auto user_agent = peer.user_agent; - if (user_agent.length() > 14) { - user_agent = user_agent.substr(0, 14) + ".."; - } - if (user_agent.empty()) { - user_agent = "Unknown"; - } - - // Preferred indicator - auto preferred_indicator = peer.is_preferred ? - text("★") | color(colors::bch_green) | bold : - text(" "); - - peer_rows.push_back(hbox({ - direction, - text(peer.address) | color(colors::white) | size(WIDTH, EQUAL, 22), - text(user_agent) | color(colors::cyan) | size(WIDTH, EQUAL, 16), - text(format_number(peer.start_height)) | color(colors::gray) | size(WIDTH, EQUAL, 10), - text(format_bytes(peer.bytes_received)) | color(colors::green) | size(WIDTH, EQUAL, 10), - text(format_bytes(peer.bytes_sent)) | color(colors::blue) | size(WIDTH, EQUAL, 10), - text(ping_str) | color(ping_col) | size(WIDTH, EQUAL, 8), - text(time_str) | color(colors::gray) | size(WIDTH, EQUAL, 8), - })); - } - } - - // Summary footer - Elements summary; - summary.push_back(separator() | color(colors::dark_gray)); - summary.push_back(hbox({ - text("Total: ") | color(colors::gray), - text(std::to_string(status_.peers_outbound + status_.peers_inbound)) | bold | color(colors::white), - text(" peers (") | color(colors::gray), - text("↑" + std::to_string(status_.peers_outbound)) | color(colors::cyan), - text(" out, ") | color(colors::gray), - text("↓" + std::to_string(status_.peers_inbound)) | color(colors::kth_violet), - text(" in)") | color(colors::gray), - filler(), - text("Avg ping: ") | color(colors::gray), - text(status_.avg_ping_ms > 0 ? std::to_string(status_.avg_ping_ms) + "ms" : "-") | - color(status_.avg_ping_ms < 100 ? colors::green : - status_.avg_ping_ms < 300 ? colors::orange : colors::red), - })); - - return vbox({ - render_header_bar(), - separator() | color(colors::dark_gray), - window(text(" ⚡ CONNECTED PEERS ") | bold | color(colors::cyan), - vbox(peer_rows) | flex) | flex, - vbox(summary), - separator() | color(colors::dark_gray), - render_navigation_bar(), - render_footer(), - }) | border | color(colors::kth_purple); + return render_placeholder("NETWORK"); } Element tui_dashboard::render_blockchain_screen() { @@ -642,56 +526,7 @@ Element tui_dashboard::render_mempool_screen() { } Element tui_dashboard::render_logs_screen() { - Elements log_lines; - - if (status_.recent_logs.empty()) { - log_lines.push_back(text(" No logs yet...") | color(colors::gray) | dim); - } else { - // Show last N logs that fit - size_t const max_visible = 20; - size_t start = status_.recent_logs.size() > max_visible ? - status_.recent_logs.size() - max_visible : 0; - - for (size_t i = start; i < status_.recent_logs.size(); ++i) { - auto const& log = status_.recent_logs[i]; - - // Color based on log level (detect from content) - Color log_color = colors::white; - if (log.find("[error]") != std::string::npos || - log.find("[ERROR]") != std::string::npos || - log.find("Error") != std::string::npos) { - log_color = colors::red; - } else if (log.find("[warn]") != std::string::npos || - log.find("[WARN]") != std::string::npos || - log.find("Warning") != std::string::npos) { - log_color = colors::orange; - } else if (log.find("[info]") != std::string::npos || - log.find("[INFO]") != std::string::npos) { - log_color = colors::cyan; - } else if (log.find("[debug]") != std::string::npos || - log.find("[DEBUG]") != std::string::npos) { - log_color = colors::gray; - } - - // Truncate long lines - std::string display_log = log; - if (display_log.length() > 100) { - display_log = display_log.substr(0, 97) + "..."; - } - - log_lines.push_back(text(display_log) | color(log_color)); - } - } - - return vbox({ - render_header_bar(), - separator() | color(colors::dark_gray), - window(text(" 📋 LOGS ") | bold | color(colors::kth_violet), - vbox(log_lines) | flex) | flex, - separator() | color(colors::dark_gray), - render_navigation_bar(), - render_footer(), - }) | border | color(colors::kth_purple); + return render_placeholder("LOGS"); } Element tui_dashboard::render_terminal_screen() { @@ -968,9 +803,8 @@ Element tui_dashboard::render_network_panel() { Elements rows; - // Header: Peers count and listen port rows.push_back(hbox({ - text("○ ") | color(total_peers > 0 ? colors::green : colors::red), + text("⬡ ") | color(total_peers > 0 ? colors::green : colors::red), text("Peers: ") | color(colors::gray), text(std::to_string(total_peers)) | bold | color(total_peers > 0 ? colors::green : colors::red), text(" (") | color(colors::dark_gray), @@ -979,53 +813,31 @@ Element tui_dashboard::render_network_panel() { text(")") | color(colors::dark_gray), })); - rows.push_back(hbox({ - text("Listen: ") | color(colors::gray), - text(":8333") | color(colors::white), // TODO: get from config - })); - rows.push_back(text("")); - // Connected peers header - rows.push_back(text("Connected peers:") | color(colors::gray)); - - // Show each peer - if (status_.peers.empty()) { - rows.push_back(text(" (none)") | color(colors::dark_gray) | dim); - } else { - for (auto const& peer : status_.peers) { - // Direction - std::string direction = peer.is_inbound ? "IN " : "OUT"; - auto dir_color = peer.is_inbound ? colors::kth_violet : colors::cyan; - - // User agent - truncate if needed - std::string agent = peer.user_agent; - if (agent.empty()) agent = "Unknown"; - if (agent.length() > 12) agent = agent.substr(0, 12); - - // Format: OUT ip:port UserAgent H:height ↓recv ↑sent pingms - auto ping_color = peer.ping_ms == 0 ? colors::gray : - peer.ping_ms < 200 ? colors::green : - peer.ping_ms < 500 ? colors::orange : colors::red; + rows.push_back(hbox({ + text("↓ ") | color(colors::green) | bold, + text(format_bytes_speed(status_.bytes_received)) | color(colors::green), + text(" "), + text("↑ ") | color(colors::blue) | bold, + text(format_bytes_speed(status_.bytes_sent)) | color(colors::blue), + })); - auto ping_str = peer.ping_ms > 0 ? - std::to_string(peer.ping_ms) + "ms" : "-"; + if (status_.total_bytes_received > 0 || status_.total_bytes_sent > 0) { + rows.push_back(hbox({ + text("Total: ") | color(colors::gray), + text("↓" + format_bytes(status_.total_bytes_received)) | color(colors::green) | dim, + text(" ↑" + format_bytes(status_.total_bytes_sent)) | color(colors::blue) | dim, + })); + } - rows.push_back(hbox({ - text(direction + " ") | color(dir_color), - text(peer.address) | color(colors::white), - text(" "), - text(agent) | color(colors::cyan), - text(" "), - text("H:" + format_number(peer.start_height)) | color(colors::gray), - text(" "), - text("↓" + format_bytes(peer.bytes_received)) | color(colors::green), - text(" "), - text("↑" + format_bytes(peer.bytes_sent)) | color(colors::blue), - text(" "), - text(ping_str) | color(ping_color), - })); - } + if (status_.avg_ping_ms > 0) { + rows.push_back(hbox({ + text("Ping: ") | color(colors::gray), + text(std::to_string(status_.avg_ping_ms) + "ms") | color( + status_.avg_ping_ms < 100 ? colors::green : + status_.avg_ping_ms < 500 ? colors::orange : colors::red), + })); } return window(text(" ⚡ NETWORK ") | bold | color(colors::cyan), vbox(rows) | flex) | flex; diff --git a/src/node-exe/src/tui_dashboard.hpp b/src/node-exe/src/tui_dashboard.hpp index 7830876f..b6edbb76 100644 --- a/src/node-exe/src/tui_dashboard.hpp +++ b/src/node-exe/src/tui_dashboard.hpp @@ -32,19 +32,6 @@ enum class screen_id { terminal, // C64-style terminal }; -/// Per-peer information for TUI display -struct peer_info { - std::string address; // IP:port - std::string user_agent; // Short user agent (e.g., "BCHN:28.0.1") - uint32_t start_height{0}; // Peer's reported height - size_t bytes_received{0}; // Total bytes received from peer - size_t bytes_sent{0}; // Total bytes sent to peer - uint32_t ping_ms{0}; // Last ping latency in ms - bool is_inbound{false}; // true if peer connected to us - bool is_preferred{false}; // true if preferred for download (BCHN fPreferredDownload) - std::chrono::seconds connected_duration{0}; // How long connected -}; - /// Node status for TUI display - Mining focused struct node_status { // Version & Network @@ -85,9 +72,6 @@ struct node_status { size_t total_bytes_sent{0}; // total bytes size_t avg_ping_ms{0}; - // Connected peers (for Network screen) - std::vector peers; - // Mempool size_t mempool_tx_count{0}; size_t mempool_size_bytes{0}; @@ -103,9 +87,6 @@ struct node_status { size_t db_cache_size{0}; double cpu_usage{0.0}; size_t memory_usage{0}; - - // Logs (for Logs screen) - std::vector recent_logs; }; /// TUI Dashboard using FTXUI - Multi-screen with animations @@ -125,9 +106,6 @@ class tui_dashboard { /// Update node status (thread-safe) void update_status(node_status const& status); - /// Add a log message (thread-safe) - void add_log(std::string const& message); - /// Check if TUI is running bool is_running() const; diff --git a/src/node/CMakeLists.txt b/src/node/CMakeLists.txt index cd2e6f1e..9e82fdc2 100644 --- a/src/node/CMakeLists.txt +++ b/src/node/CMakeLists.txt @@ -153,10 +153,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") src/utility/reservation.cpp src/utility/reservations.cpp - src/block_download_coordinator.cpp - src/parallel_sync.cpp - src/block_download_coordinator_v2.cpp - src/parallel_sync_v2.cpp ) endif() @@ -188,10 +184,6 @@ set(kth_headers include/kth/node/full_node.hpp include/kth/node/sync_session.hpp include/kth/node/parser.hpp - include/kth/node/block_download_coordinator.hpp - include/kth/node/parallel_sync.hpp - include/kth/node/block_download_coordinator_v2.hpp - include/kth/node/parallel_sync_v2.hpp ) add_library(${PROJECT_NAME} ${MODE} ${kth_sources} ${kth_headers}) diff --git a/src/node/data/bn.cfg b/src/node/data/bn.cfg index c8f55735..6d4d8a88 100644 --- a/src/node/data/bn.cfg +++ b/src/node/data/bn.cfg @@ -39,8 +39,8 @@ validate_checksum = false inbound_port = 8333 # The target number of incoming network connections, defaults to 0. inbound_connections = 0 -# The target number of outgoing network connections, defaults to 8. -outbound_connections = 8 +# The target number of outgoing network connections, defaults to 2. +outbound_connections = 2 # The attempt limit for manual connection establishment, defaults to 0 (forever). manual_attempt_limit = 0 # The number of concurrent attempts to establish one connection, defaults to 5. diff --git a/src/node/include/kth/node.hpp b/src/node/include/kth/node.hpp index 098adff4..e3494c1a 100644 --- a/src/node/include/kth/node.hpp +++ b/src/node/include/kth/node.hpp @@ -22,8 +22,6 @@ #include #include #include -#include -#include #include diff --git a/src/node/include/kth/node/block_download_coordinator.hpp b/src/node/include/kth/node/block_download_coordinator.hpp deleted file mode 100644 index a8c6e58f..00000000 --- a/src/node/include/kth/node/block_download_coordinator.hpp +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP -#define KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP - -// ============================================================================= -// Block Download Coordinator - Parallel Block Download Management -// ============================================================================= -// -// This class coordinates parallel block downloads across multiple peers: -// -// DESIGN: -// ------- -// - Central coordinator assigns block heights to peers -// - Each peer can have up to MAX_BLOCKS_PER_PEER blocks in-flight -// - Blocks may arrive out-of-order; buffered until ready for validation -// - Validation happens in-order via a separate pipeline -// -// FLOW: -// ----- -// 1. Peer calls claim_blocks() to get next blocks to download -// 2. Peer sends getdata for claimed blocks -// 3. Peer receives blocks and calls block_received() -// 4. Coordinator buffers out-of-order blocks -// 5. Validation pipeline consumes blocks in order -// -// RECOVERY: -// --------- -// - On peer disconnect: reassign its in-flight blocks -// - On timeout: reassign stalled blocks to other peers -// - On validation failure: stop sync and report error -// -// ============================================================================= - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include - -namespace kth::node { - -/// Configuration for parallel block download -struct parallel_download_config { - /// Maximum blocks in-flight per peer (BCHN: 16) - size_t max_blocks_per_peer{16}; - - /// Global download window - max blocks ahead of validation - size_t global_window{1024}; - - /// Timeout for individual block download - std::chrono::seconds block_timeout{60}; - - /// Timeout before reassigning stalled blocks - std::chrono::seconds stall_timeout{10}; - - /// How often to check for stalled downloads - std::chrono::seconds timeout_check_interval{1}; -}; - -/// Block download coordinator - manages parallel downloads across peers -class KND_API block_download_coordinator { -public: - using block_const_ptr = domain::message::block::const_ptr; - using peer_ptr = network::peer_session::ptr; - - /// Construct coordinator for a block range - /// @param chain Blockchain for validation - /// @param organizer Header organizer (has the header index) - /// @param start_height First block to download (usually 1 for IBD) - /// @param target_height Last block to download - /// @param executor Executor for internal channel - /// @param config Download configuration - block_download_coordinator( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - uint32_t start_height, - uint32_t target_height, - ::asio::any_io_executor executor, - parallel_download_config const& config = {}); - - ~block_download_coordinator(); - - // Non-copyable - block_download_coordinator(block_download_coordinator const&) = delete; - block_download_coordinator& operator=(block_download_coordinator const&) = delete; - - // ------------------------------------------------------------------------- - // Peer Interface - // ------------------------------------------------------------------------- - - /// Claim blocks for a peer to download - /// @param peer The peer claiming blocks - /// @param max_count Maximum blocks to claim (typically 16) - /// @return Vector of {height, hash} pairs to download, empty if none available - [[nodiscard]] - ::asio::awaitable>> claim_blocks( - peer_ptr const& peer, - size_t max_count); - - /// Report that a block was received - /// @param height Block height - /// @param hash Block hash - /// @param block The received block - ::asio::awaitable block_received( - uint32_t height, - hash_digest const& hash, - block_const_ptr block); - - /// Report that a peer disconnected - reassign its blocks - ::asio::awaitable peer_disconnected(peer_ptr const& peer); - - // ------------------------------------------------------------------------- - // Validation Pipeline - // ------------------------------------------------------------------------- - - /// Get next block ready for validation (in-order) - /// Blocks until a block is available or sync is complete/failed - /// @return Block to validate, or nullopt if sync complete/failed - [[nodiscard]] - ::asio::awaitable>> next_block_to_validate(); - - /// Report validation result - void validation_complete(uint32_t height, code result); - - // ------------------------------------------------------------------------- - // Status & Control - // ------------------------------------------------------------------------- - - /// Check for stalled downloads and reassign - void check_timeouts(); - - /// Check if all blocks have been downloaded and validated - [[nodiscard]] - bool is_complete() const; - - /// Check if sync has failed - [[nodiscard]] - bool has_failed() const; - - /// Check if coordinator was stopped externally - [[nodiscard]] - bool is_stopped() const; - - /// Get failure error code - [[nodiscard]] - code failure_reason() const; - - /// Stop the coordinator (cancel pending operations) - void stop(); - - /// Get current progress - struct progress { - uint32_t blocks_downloaded; - uint32_t blocks_validated; - uint32_t blocks_in_flight; - uint32_t blocks_pending; // Downloaded but not yet validated - uint32_t active_peers; // Peers with blocks in-flight - uint32_t start_height; - uint32_t target_height; - std::chrono::steady_clock::time_point start_time; - }; - - [[nodiscard]] - progress get_progress() const; - -private: - // Get hash for a block height from header organizer - hash_digest get_block_hash(uint32_t height) const; - - // Try to push ready blocks to validation channel - void flush_pending_to_validation(); - - // Mark sync as failed - void set_failed(code reason); - - // Configuration - parallel_download_config config_; - - // Blockchain access - blockchain::block_chain& chain_; - blockchain::header_organizer& organizer_; - - // Range to download - uint32_t const start_height_; - uint32_t const target_height_; - - // Strand for serializing access to shared state (replaces mutex) - // All peer operations (claim_blocks, block_received, etc.) run on this strand - ::asio::strand<::asio::any_io_executor> strand_; - std::atomic stopped_{false}; - std::atomic failed_{false}; - code failure_reason_{error::success}; - - // Assignment state - uint32_t next_height_to_assign_; // Next height to assign to a peer - - // In-flight tracking: height -> {peer, request_time} - struct assignment { - peer_ptr peer; - std::chrono::steady_clock::time_point requested_at; - }; - boost::unordered_flat_map in_flight_; - - // Out-of-order buffer: height -> block - boost::unordered_flat_map pending_blocks_; - - // Validation state - uint32_t next_height_to_validate_; - std::atomic blocks_validated_{0}; - - // Timing - std::chrono::steady_clock::time_point start_time_; - - // Channel for validation pipeline - using validation_channel = ::asio::experimental::concurrent_channel< - void(std::error_code, std::pair)>; - std::unique_ptr validation_queue_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP diff --git a/src/node/include/kth/node/block_download_coordinator_v2.hpp b/src/node/include/kth/node/block_download_coordinator_v2.hpp deleted file mode 100644 index 1e3fc839..00000000 --- a/src/node/include/kth/node/block_download_coordinator_v2.hpp +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP -#define KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP - -// ============================================================================= -// Block Download Coordinator V2 - Lock-Free Parallel Block Download -// ============================================================================= -// -// Simplified coordinator using atomic operations instead of mutex/strand. -// -// DESIGN: -// ------- -// - Uses a slot-based system where each slot represents a chunk of 16 blocks -// - Slots have 3 states: FREE (0), IN_PROGRESS (1), COMPLETED (2) -// - Claim operation is lock-free using CAS -// - Timeout checker can reset stalled slots back to FREE -// - When all slots in a round are COMPLETED, advance to next round -// -// FLOW: -// ----- -// 1. Peer calls claim_chunk() to get a chunk_id -// 2. Peer calculates block range: [start + chunk_id*16, start + chunk_id*16 + 15] -// 3. Peer fetches hashes from header_index and downloads blocks -// 4. Peer calls chunk_completed(chunk_id) when done -// 5. Timeout checker periodically resets stalled IN_PROGRESS slots -// -// ============================================================================= - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace kth::node { - -/// Configuration for parallel block download v2 -struct parallel_download_config_v2 { - /// Blocks per chunk (matches Bitcoin protocol limit) - size_t chunk_size{16}; - - /// Slots per round = max_peers * multiplier - /// Higher = less frequent round resets - size_t slots_multiplier{100}; - - /// Maximum peers expected - size_t max_peers{8}; - - /// Timeout before a slot is considered stalled - std::chrono::seconds stall_timeout{30}; - - /// How often to check for stalled downloads - std::chrono::seconds timeout_check_interval{5}; -}; - -/// Lock-free block download coordinator -class KND_API block_download_coordinator_v2 { -public: - using block_const_ptr = domain::message::block::const_ptr; - - /// Slot states - enum SlotState : uint8_t { - FREE = 0, // Available for assignment - IN_PROGRESS = 1, // Assigned, waiting for completion - COMPLETED = 2 // Blocks received successfully - }; - - /// Construct coordinator for a block range - block_download_coordinator_v2( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - uint32_t start_height, - uint32_t target_height, - ::asio::any_io_executor executor, - parallel_download_config_v2 const& config = {}); - - ~block_download_coordinator_v2(); - - // Non-copyable - block_download_coordinator_v2(block_download_coordinator_v2 const&) = delete; - block_download_coordinator_v2& operator=(block_download_coordinator_v2 const&) = delete; - - // ------------------------------------------------------------------------- - // Peer Interface (Lock-Free) - // ------------------------------------------------------------------------- - - /// Claim a chunk to download - /// @return chunk_id, or nullopt if sync complete - [[nodiscard]] - std::optional claim_chunk(); - - /// Get block range for a chunk - /// @return {start_height, end_height} for the chunk - [[nodiscard]] - std::pair chunk_range(uint32_t chunk_id) const; - - /// Get block hash for a height (from header index) - [[nodiscard]] - hash_digest get_block_hash(uint32_t height) const; - - /// Report that a chunk was completed successfully - void chunk_completed(uint32_t chunk_id); - - /// Report that a chunk failed (will be retried) - void chunk_failed(uint32_t chunk_id); - - // ------------------------------------------------------------------------- - // Block Reception & Validation - // ------------------------------------------------------------------------- - - /// Report a received block for validation pipeline - void block_received(uint32_t height, block_const_ptr block); - - /// Get next block ready for validation (in-order) - [[nodiscard]] - ::asio::awaitable>> next_block_to_validate(); - - /// Report validation result - void validation_complete(uint32_t height, code result); - - // ------------------------------------------------------------------------- - // Status & Control - // ------------------------------------------------------------------------- - - /// Check for stalled downloads and reset them - void check_timeouts(); - - /// Check if all blocks have been validated - [[nodiscard]] - bool is_complete() const; - - /// Check if sync has failed - [[nodiscard]] - bool has_failed() const; - - /// Check if coordinator was stopped - [[nodiscard]] - bool is_stopped() const; - - /// Get failure reason - [[nodiscard]] - code failure_reason() const; - - /// Stop the coordinator - void stop(); - - /// Progress information - struct progress { - uint32_t chunks_assigned; - uint32_t chunks_completed; - uint32_t chunks_in_progress; - uint32_t blocks_validated; - uint32_t blocks_pending; - uint32_t current_round; - uint32_t start_height; - uint32_t target_height; - uint32_t active_peers; - std::chrono::steady_clock::time_point start_time; - }; - - /// Register/unregister active download peers - void peer_started(); - void peer_stopped(); - - [[nodiscard]] - progress get_progress() const; - -private: - /// Try to advance to next round if all slots completed - void try_advance_round(); - - /// Flush pending blocks to validation channel - void flush_pending_to_validation(); - - /// Set sync as failed - void set_failed(code reason); - - /// Get current time in milliseconds - static uint64_t now_ms(); - - // Configuration - parallel_download_config_v2 config_; - size_t slots_per_round_; - - // Blockchain access - blockchain::block_chain& chain_; - blockchain::header_organizer& organizer_; - - // Range to download - uint32_t const start_height_; - uint32_t const target_height_; - uint32_t const total_chunks_; - - // ========================================================================= - // Lock-free slot management - // ========================================================================= - std::atomic round_{0}; - std::vector> slots_; - std::vector> slot_times_; // timestamp when assigned - std::atomic resetting_{false}; - - // Status - std::atomic stopped_{false}; - std::atomic failed_{false}; - code failure_reason_{error::success}; - std::atomic chunks_completed_{0}; - std::atomic blocks_validated_{0}; - std::atomic active_peers_{0}; - - // Validation pipeline - needs synchronization for out-of-order blocks - std::mutex validation_mutex_; - uint32_t next_height_to_validate_; - boost::unordered_flat_map pending_blocks_; - - // Timing - std::chrono::steady_clock::time_point start_time_; - - // Channel for validation pipeline - using validation_channel = ::asio::experimental::concurrent_channel< - void(std::error_code, std::pair)>; - std::unique_ptr validation_queue_; -}; - -} // namespace kth::node - -#endif // KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP diff --git a/src/node/include/kth/node/executor/executor.hpp b/src/node/include/kth/node/executor/executor.hpp index a4b272bc..618fe4b0 100644 --- a/src/node/include/kth/node/executor/executor.hpp +++ b/src/node/include/kth/node/executor/executor.hpp @@ -6,11 +6,8 @@ #define KTH_NODE_EXE_EXECUTOR_HPP_ #include -#include -#include #include #include -#include #include #include @@ -21,132 +18,121 @@ #include #include -#include namespace kth::node { -/// Executor - manages the lifecycle of a full node -/// -/// The executor owns the io_context and runs it internally in its own thread. -/// This design allows the node to be used as a library from any language -/// (via C API) without the caller needing to manage async execution. -/// -/// Usage: -/// executor exec(config); -/// auto ec = exec.start(); // blocks until node is ready -/// // ... use node ... -/// exec.stop(); // blocks until node is stopped -/// -class executor { -public: - using start_handler = std::function; - using stop_handler = std::function; - +struct executor { executor(kth::node::configuration const& config, bool stdout_enabled = true); ~executor(); executor(executor const&) = delete; - executor& operator=(executor const&) = delete; - - // ------------------------------------------------------------------------- - // Lifecycle - Async versions (callback-based, for C API and non-blocking use) - // ------------------------------------------------------------------------- - - /// Start the node asynchronously - /// @param handler Called when node is ready (or failed to start) - void start_async(start_handler handler); - - /// Stop the node asynchronously - /// @param handler Called when node is fully stopped (optional) - void stop_async(stop_handler handler = nullptr); + void operator=(executor const&) = delete; - // ------------------------------------------------------------------------- - // Lifecycle - Sync versions (blocking, for simple use cases) - // ------------------------------------------------------------------------- - - /// Start the node and block until ready - /// @return Error code (success if node started successfully) - [[nodiscard]] - code start(); +#if ! defined(KTH_DB_READONLY) + bool do_initchain(std::string_view extra); +#endif - /// Stop the node and block until fully stopped - void stop(); +#if ! defined(KTH_DB_READONLY) + /// Initialize and run the node, blocking until signal or error + bool init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler); - /// Wait for stop signal (SIGINT/SIGTERM) - /// Blocks until signal received - void wait_for_stop_signal(); + /// Initialize and run the node without blocking + bool init_run(std::string_view extra, start_modules mod, kth::handle0 handler); +#endif - // ------------------------------------------------------------------------- - // State - // ------------------------------------------------------------------------- + /// Signal the node to stop + void signal_stop(); - /// Check if node is currently running (started and not stopped) - [[nodiscard]] - bool running() const; + /// Stop and cleanup the node (must be called from main thread) + bool close(); - /// Check if node has been started (may still be starting up) - [[nodiscard]] - bool started() const; + /// Access the full node + kth::node::full_node& node(); + kth::node::full_node const& node() const; /// Check if node is stopped - [[nodiscard]] bool stopped() const; - // ------------------------------------------------------------------------- - // Node access (only valid when running) - // ------------------------------------------------------------------------- - - [[nodiscard]] - kth::node::full_node& node(); - - [[nodiscard]] - kth::node::full_node const& node() const; - - // ------------------------------------------------------------------------- - // Initialization helpers - // ------------------------------------------------------------------------- + void print_version(std::string_view extra); + void initialize_output(std::string_view extra, kth::database::db_mode_type db_mode); #if ! defined(KTH_DB_READONLY) - bool do_initchain(std::string_view extra); bool init_directory(std::error_code& ec); std::error_code init_directory_if_necessary(); #endif bool verify_directory(); - void print_version(std::string_view extra); - void initialize_output(std::string_view extra, kth::database::db_mode_type db_mode); private: + bool wait_for_signal_and_close(); void print_ascii_art(); - void start_io_thread(); - void stop_io_thread(); - // Configuration + static + void stop(kth::code const& ec); + + static + void handle_stop(int code); + + void run_node_async(start_modules mod); + + // Termination state + static std::promise stopping_; + bool stdout_enabled_; kth::node::configuration config_; - - // Node instance kth::node::full_node::ptr node_; + kth::handle0 run_handler_; - // IO context runs in its own thread + // IO context for running coroutines ::asio::io_context io_context_; - using work_guard_type = ::asio::executor_work_guard<::asio::io_context::executor_type>; - std::optional work_guard_; std::thread io_thread_; + std::atomic running_{false}; +}; - // State tracking - enum class state { stopped, starting, running, stopping }; - std::atomic state_{state::stopped}; - - // Synchronization for sync versions - std::mutex start_mutex_; - std::condition_variable start_cv_; - code start_result_{error::success}; +// Localizable messages. +#define KTH_SETTINGS_MESSAGE "These are the configuration settings that can be set." +#define KTH_INFORMATION_MESSAGE "Runs a Bitcoin Cash full-node." +#define KTH_UNINITIALIZED_CHAIN "The {} directory is not initialized, run: kth --initchain" +#define KTH_INITIALIZING_CHAIN "Please wait while initializing {} directory..." +#define KTH_INITCHAIN_NEW "Failed to create directory {} with error, '{}'." +#define KTH_INITCHAIN_EXISTS "Failed because the directory {} already exists." +#define KTH_INITCHAIN_TRY "Failed to test directory {} with error, '{}'." +#define KTH_INITCHAIN_COMPLETE "Completed initialization." +#define KTH_INITCHAIN_FAILED "Error creating database files." + +#define KTH_NODE_INTERRUPT "Press CTRL-C to stop the node." +#define KTH_NODE_STARTING "Please wait while the node is starting..." +#define KTH_NODE_START_FAIL "Node failed to start with error, {}." +#define KTH_NODE_SEEDED "Seeding is complete." +#define KTH_NODE_STARTED "Node is started." + +#define KTH_NODE_SIGNALED "Stop signal detected (code: {})." +#define KTH_NODE_STOPPING "Please wait while the node is stopping..." +#define KTH_NODE_STOP_FAIL "Node failed to stop properly, see log." +#define KTH_NODE_STOPPED "Node stopped successfully." +#define KTH_GOOD_BYE "Good bye!" + +#define KTH_RPC_STOPPING "RPC-ZMQ service is stopping..." +#define KTH_RPC_STOPPED "RPC-ZMQ service stopped successfully" + +#define KTH_USING_CONFIG_FILE "Using config file: {}" +#define KTH_USING_DEFAULT_CONFIG "Using default configuration settings." + +#ifdef NDEBUG +#define KTH_VERSION_MESSAGE "Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}" +#else +#define KTH_VERSION_MESSAGE "Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}\n (Debug Build)" +#endif - // Tracks when run() coroutine completes (for safe shutdown) - std::promise run_completed_promise_; - std::future run_completed_future_; -}; +#define KTH_VERSION_MESSAGE_INIT "Knuth v{}" +#define KTH_CRYPTOCURRENCY_INIT "Currency: {} - {}." +#define KTH_MICROARCHITECTURE_INIT "Optimized for microarchitecture: {}." +#define KTH_MARCH_EXTS_INIT "Built for CPU instructions/extensions: {}." +#define KTH_DB_TYPE_INIT "Database type: {}." +#define KTH_DEBUG_BUILD_INIT "(Debug Build)" +#define KTH_NETWORK_INIT "Network: {0} ({1} - {1:#x})." +#define KTH_BLOCKCHAIN_CORES_INIT "Blockchain configured to use {} threads." +#define KTH_NETWORK_CORES_INIT "Networking configured to use {} threads." } // namespace kth::node diff --git a/src/node/include/kth/node/full_node.hpp b/src/node/include/kth/node/full_node.hpp index 3ef94c2f..8b329a54 100644 --- a/src/node/include/kth/node/full_node.hpp +++ b/src/node/include/kth/node/full_node.hpp @@ -213,12 +213,6 @@ class KND_API full_node : public multi_crypto_setter { block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr outgoing); - // Background task coroutines (for structured concurrency) - ::asio::awaitable run_blockchain_subscriber(); -#if ! defined(__EMSCRIPTEN__) - ::asio::awaitable run_sync(); -#endif - // Configuration references (stored in configuration object) node::settings const& node_settings_; blockchain::settings const& chain_settings_; @@ -229,7 +223,6 @@ class KND_API full_node : public multi_crypto_setter { // Core components (composition, not inheritance) #if ! defined(__EMSCRIPTEN__) - kth::network::settings network_settings_; // Own copy, allows modification (e.g., user_agent) kth::network::p2p_node network_; #endif blockchain::block_chain chain_; diff --git a/src/node/include/kth/node/parallel_sync.hpp b/src/node/include/kth/node/parallel_sync.hpp deleted file mode 100644 index dc138f3b..00000000 --- a/src/node/include/kth/node/parallel_sync.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PARALLEL_SYNC_HPP -#define KTH_NODE_PARALLEL_SYNC_HPP - -#include -#include -#include -#include -#include - -#include - -namespace kth::node { - -/// Result of parallel block sync -struct parallel_sync_result { - code error; - uint32_t blocks_downloaded{0}; - uint32_t blocks_validated{0}; - uint32_t final_height{0}; -}; - -/// Download and validate blocks in parallel from multiple peers -/// @param chain Blockchain for validation -/// @param organizer Header organizer (contains header index) -/// @param network P2P network for peer access -/// @param start_height First block to download -/// @param target_height Last block to download -/// @param config Download configuration -[[nodiscard]] -KND_API ::asio::awaitable parallel_block_sync( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - network::p2p_node& network, - uint32_t start_height, - uint32_t target_height, - parallel_download_config const& config = {}); - -} // namespace kth::node - -#endif // KTH_NODE_PARALLEL_SYNC_HPP diff --git a/src/node/include/kth/node/parallel_sync_v2.hpp b/src/node/include/kth/node/parallel_sync_v2.hpp deleted file mode 100644 index 0828305f..00000000 --- a/src/node/include/kth/node/parallel_sync_v2.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KTH_NODE_PARALLEL_SYNC_V2_HPP -#define KTH_NODE_PARALLEL_SYNC_V2_HPP - -#include - -#include -#include -#include -#include - -namespace kth::node { - -/// Result of parallel block sync v2 -struct parallel_sync_result_v2 { - code error{error::success}; - uint32_t blocks_downloaded{0}; - uint32_t blocks_validated{0}; - uint32_t final_height{0}; -}; - -/// Parallel block sync using lock-free coordinator v2 -/// Downloads blocks from multiple peers in parallel and validates in order -[[nodiscard]] -KND_API -::asio::awaitable parallel_block_sync_v2( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - network::p2p_node& network, - uint32_t start_height, - uint32_t target_height, - parallel_download_config_v2 const& config = {}); - -} // namespace kth::node - -#endif // KTH_NODE_PARALLEL_SYNC_V2_HPP diff --git a/src/node/include/kth/node/sync_session.hpp b/src/node/include/kth/node/sync_session.hpp index 13a58abf..eebbb28e 100644 --- a/src/node/include/kth/node/sync_session.hpp +++ b/src/node/include/kth/node/sync_session.hpp @@ -44,7 +44,6 @@ #include #include #include -#include #include @@ -87,9 +86,9 @@ struct sync_config { /// If peer doesn't respond with better chain after this, disconnect std::chrono::seconds headers_response_timeout{2 * 60}; - /// Block stalling timeout (BCHN: 10 seconds for individual blocks) - /// If a block request hasn't completed in this time, reassign to another peer - std::chrono::seconds block_stalling_timeout{10}; + /// Block stalling timeout (BCHN: 2 seconds) + /// If block download window can't move for this long, disconnect + std::chrono::seconds block_stalling_timeout{2}; /// Block download timeout base, in units of block interval (BCHN: 10 min equivalent) /// Actual timeout = block_interval * (base + per_peer * num_other_peers) @@ -114,19 +113,11 @@ class KND_API sync_session { using ptr = std::shared_ptr; /// Construct sync session - /// @param chain Blockchain reference - /// @param peer Primary peer for header sync - /// @param network Network type (mainnet/testnet) - /// @param config Sync configuration - /// @param target_height Override target height (0 = use peer's start_height) - /// @param p2p_node Optional p2p_node for parallel block download (nullptr = sequential) sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, - sync_config const& config = {}, - size_t target_height = 0, - network::p2p_node* p2p_node = nullptr); + sync_config const& config = {}); /// Run synchronization with peer /// Returns when synced or on error @@ -150,13 +141,9 @@ class KND_API sync_session { ::asio::awaitable sync_headers_batch(); ::asio::awaitable sync_blocks(std::vector const& hashes); - // Background task to persist headers from header_index to database - ::asio::awaitable persist_headers_to_db(size_t start_height, size_t end_height); - blockchain::block_chain& chain_; blockchain::header_organizer organizer_; network::peer_session::ptr peer_; - network::p2p_node* p2p_node_; // Optional: for parallel block download sync_config config_; size_t header_height_{0}; // Current header-sync height (from DB at start) @@ -177,16 +164,12 @@ class KND_API sync_session { }; /// Create a sync session for a peer -/// @param target_height Override target height (0 = use peer's start_height) -/// @param p2p_node Optional p2p_node for parallel block download (nullptr = sequential) [[nodiscard]] KND_API sync_session::ptr make_sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, - sync_config const& config = {}, - size_t target_height = 0, - network::p2p_node* p2p_node = nullptr); + sync_config const& config = {}); /// Run sync with the best available peer /// Selects peer based on start_height from version message diff --git a/src/node/src/block_download_coordinator.cpp b/src/node/src/block_download_coordinator.cpp deleted file mode 100644 index 9881cc03..00000000 --- a/src/node/src/block_download_coordinator.cpp +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include - -#include -#include -#include -#include - -namespace kth::node { - -block_download_coordinator::block_download_coordinator( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - uint32_t start_height, - uint32_t target_height, - ::asio::any_io_executor executor, - parallel_download_config const& config) - : config_(config) - , chain_(chain) - , organizer_(organizer) - , start_height_(start_height) - , target_height_(target_height) - , strand_(::asio::make_strand(executor)) - , next_height_to_assign_(start_height) - , next_height_to_validate_(start_height) - , start_time_(std::chrono::steady_clock::now()) - , validation_queue_(std::make_unique(executor, config.global_window)) -{ - spdlog::debug("[coordinator] Created for blocks {}-{} ({} blocks)", - start_height, target_height, target_height - start_height + 1); -} - -block_download_coordinator::~block_download_coordinator() { - stop(); -} - -// ============================================================================= -// Peer Interface -// ============================================================================= - -::asio::awaitable>> block_download_coordinator::claim_blocks( - peer_ptr const& peer, - size_t max_count) -{ - // Execute on strand to serialize access to shared state - co_return co_await ::asio::co_spawn(strand_, [this, peer, max_count]() -> ::asio::awaitable>> { - if (stopped_ || failed_) { - co_return std::vector>{}; - } - - // Count how many blocks this peer already has in-flight - size_t peer_in_flight = 0; - for (auto const& [height, assignment] : in_flight_) { - if (assignment.peer == peer) { - ++peer_in_flight; - } - } - - // Limit per peer - if (peer_in_flight >= config_.max_blocks_per_peer) { - spdlog::debug("[coordinator] Peer [{}] at limit ({} >= {} max)", - peer->authority(), peer_in_flight, config_.max_blocks_per_peer); - co_return std::vector>{}; - } - - size_t can_claim = std::min(max_count, config_.max_blocks_per_peer - peer_in_flight); - - // Check in-flight limit (don't count pending - those are already downloaded) - size_t total_in_flight = in_flight_.size(); - if (total_in_flight >= config_.global_window) { - spdlog::debug("[coordinator] In-flight window full for peer [{}]: {} >= {} window", - peer->authority(), total_in_flight, config_.global_window); - co_return std::vector>{}; - } - - can_claim = std::min(can_claim, config_.global_window - total_in_flight); - - std::vector> result; - result.reserve(can_claim); - - auto now = std::chrono::steady_clock::now(); - - while (result.size() < can_claim && next_height_to_assign_ <= target_height_) { - uint32_t height = next_height_to_assign_++; - - // Get hash from header organizer - auto hash = get_block_hash(height); - if (hash == null_hash) { - spdlog::warn("[coordinator] No header hash for height {}", height); - set_failed(error::not_found); - break; - } - - // Track assignment - in_flight_[height] = {peer, now}; - result.emplace_back(height, hash); - } - - if (!result.empty()) { - spdlog::debug("[coordinator] Peer [{}] claimed {} blocks ({}-{})", - peer->authority(), result.size(), - result.front().first, result.back().first); - } - - co_return result; - }, ::asio::use_awaitable); -} - -::asio::awaitable block_download_coordinator::block_received( - uint32_t height, - hash_digest const& hash, - block_const_ptr block) -{ - // Execute on strand to serialize access to shared state - co_await ::asio::co_spawn(strand_, [this, height, hash, block = std::move(block)]() -> ::asio::awaitable { - if (stopped_ || failed_) { - co_return; - } - - // Remove from in-flight - auto it = in_flight_.find(height); - if (it != in_flight_.end()) { - in_flight_.erase(it); - } - - // Store in pending buffer - pending_blocks_[height] = std::move(block); - - spdlog::trace("[coordinator] Block {} received, {} pending, next to validate: {}", - height, pending_blocks_.size(), next_height_to_validate_); - - // Try to push ready blocks to validation - flush_pending_to_validation(); - }, ::asio::use_awaitable); -} - -::asio::awaitable block_download_coordinator::peer_disconnected(peer_ptr const& peer) { - // Execute on strand to serialize access to shared state - co_await ::asio::co_spawn(strand_, [this, peer]() -> ::asio::awaitable { - // Find and remove all blocks assigned to this peer - std::vector to_reassign; - for (auto const& [height, assignment] : in_flight_) { - if (assignment.peer == peer) { - to_reassign.push_back(height); - } - } - - for (auto height : to_reassign) { - in_flight_.erase(height); - } - - if (!to_reassign.empty()) { - // Reset assignment pointer to allow these blocks to be reclaimed - // Find the minimum height that was in-flight - uint32_t min_height = *std::min_element(to_reassign.begin(), to_reassign.end()); - if (min_height < next_height_to_assign_) { - next_height_to_assign_ = min_height; - } - - spdlog::info("[coordinator] Peer [{}] disconnected, reassigning {} blocks from height {}", - peer->authority(), to_reassign.size(), min_height); - } - }, ::asio::use_awaitable); -} - -// ============================================================================= -// Validation Pipeline -// ============================================================================= - -::asio::awaitable>> -block_download_coordinator::next_block_to_validate() -{ - if (stopped_ || failed_) { - co_return std::nullopt; - } - - // Try to receive from channel - auto [ec, block_pair] = co_await validation_queue_->async_receive( - ::asio::as_tuple(::asio::use_awaitable)); - - if (ec) { - // Channel closed or error - co_return std::nullopt; - } - - co_return block_pair; -} - -void block_download_coordinator::validation_complete(uint32_t height, code result) { - if (result != error::success) { - spdlog::error("[coordinator] Validation failed at height {}: {}", - height, result.message()); - set_failed(result); - return; - } - - ++blocks_validated_; - - // Check if we're done - if (blocks_validated_.load() >= (target_height_ - start_height_ + 1)) { - spdlog::info("[coordinator] All {} blocks validated", - target_height_ - start_height_ + 1); - validation_queue_->close(); - } -} - -// ============================================================================= -// Status & Control -// ============================================================================= - -void block_download_coordinator::check_timeouts() { - // Post to strand to serialize access - ::asio::post(strand_, [this]() { - if (stopped_ || failed_) { - return; - } - - auto now = std::chrono::steady_clock::now(); - std::vector stalled; - - for (auto const& [height, assignment] : in_flight_) { - auto elapsed = std::chrono::duration_cast( - now - assignment.requested_at); - - if (elapsed > config_.stall_timeout) { - spdlog::warn("[coordinator] Block {} stalled from [{}] ({}s)", - height, assignment.peer->authority(), elapsed.count()); - stalled.push_back(height); - } - } - - // Remove stalled assignments (will be reclaimed) - for (auto height : stalled) { - in_flight_.erase(height); - } - - if (!stalled.empty()) { - // Reset assignment to lowest stalled height - uint32_t min_height = *std::min_element(stalled.begin(), stalled.end()); - if (min_height < next_height_to_assign_) { - next_height_to_assign_ = min_height; - } - spdlog::info("[coordinator] {} stalled blocks reassigned from height {}", - stalled.size(), min_height); - } - }); -} - -bool block_download_coordinator::is_complete() const { - return blocks_validated_.load() >= (target_height_ - start_height_ + 1); -} - -bool block_download_coordinator::has_failed() const { - return failed_.load(); -} - -bool block_download_coordinator::is_stopped() const { - return stopped_.load(); -} - -code block_download_coordinator::failure_reason() const { - return failure_reason_; -} - -void block_download_coordinator::stop() { - if (stopped_.exchange(true)) { - return; // Already stopped - } - - if (validation_queue_) { - validation_queue_->close(); - } -} - -block_download_coordinator::progress block_download_coordinator::get_progress() const { - // This is called from validation pipeline which is on the strand, - // so we can safely read without additional synchronization. - // For extra safety, we use atomics for frequently changing values. - - // Count unique peers with blocks in-flight - boost::unordered_flat_set unique_peers; - for (auto const& [height, assignment] : in_flight_) { - unique_peers.insert(assignment.peer); - } - - return { - .blocks_downloaded = static_cast( - (next_height_to_assign_ - start_height_) - in_flight_.size() + pending_blocks_.size()), - .blocks_validated = blocks_validated_.load(), - .blocks_in_flight = static_cast(in_flight_.size()), - .blocks_pending = static_cast(pending_blocks_.size()), - .active_peers = static_cast(unique_peers.size()), - .start_height = start_height_, - .target_height = target_height_, - .start_time = start_time_ - }; -} - -// ============================================================================= -// Private Helpers -// ============================================================================= - -hash_digest block_download_coordinator::get_block_hash(uint32_t height) const { - // Get hash from header organizer's index - return organizer_.index().get_hash(static_cast(height)); -} - -void block_download_coordinator::flush_pending_to_validation() { - // Push as many consecutive blocks as possible to validation channel - while (!pending_blocks_.empty()) { - auto it = pending_blocks_.find(next_height_to_validate_); - if (it == pending_blocks_.end()) { - // Next block not yet received - break; - } - - // Create the pair to send WITHOUT moving from pending_blocks yet - auto block_pair = std::make_pair(next_height_to_validate_, it->second); - - // Try to send to validation channel - bool sent = validation_queue_->try_send(std::error_code{}, std::move(block_pair)); - - if (!sent) { - // Channel full - block is still safe in pending_blocks, just exit - // Rate-limit this log: only log occasionally to avoid spam - static auto last_log = std::chrono::steady_clock::now(); - auto now = std::chrono::steady_clock::now(); - if (now - last_log > std::chrono::seconds(5)) { - spdlog::warn("[coordinator] Validation channel full at height {} ({} pending)", - next_height_to_validate_, pending_blocks_.size()); - last_log = now; - } - break; - } - - // Success - now remove from pending_blocks - pending_blocks_.erase(it); - ++next_height_to_validate_; - } -} - -void block_download_coordinator::set_failed(code reason) { - if (failed_.exchange(true)) { - return; // Already failed - } - - failure_reason_ = reason; - spdlog::error("[coordinator] Sync failed: {}", reason.message()); - - if (validation_queue_) { - validation_queue_->close(); - } -} - -} // namespace kth::node diff --git a/src/node/src/block_download_coordinator_v2.cpp b/src/node/src/block_download_coordinator_v2.cpp deleted file mode 100644 index 14bcca64..00000000 --- a/src/node/src/block_download_coordinator_v2.cpp +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include - -#include - -namespace kth::node { - -block_download_coordinator_v2::block_download_coordinator_v2( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - uint32_t start_height, - uint32_t target_height, - ::asio::any_io_executor executor, - parallel_download_config_v2 const& config) - : config_(config) - , slots_per_round_(config.max_peers * config.slots_multiplier) - , chain_(chain) - , organizer_(organizer) - , start_height_(start_height) - , target_height_(target_height) - , total_chunks_((target_height - start_height + config.chunk_size) / config.chunk_size) - , slots_(slots_per_round_) - , slot_times_(slots_per_round_) - , next_height_to_validate_(start_height) - , start_time_(std::chrono::steady_clock::now()) - , validation_queue_(std::make_unique(executor, 1024)) -{ - // Initialize all slots to FREE - for (size_t i = 0; i < slots_per_round_; ++i) { - slots_[i].store(FREE, std::memory_order_relaxed); - slot_times_[i].store(0, std::memory_order_relaxed); - } - - spdlog::debug("[coordinator_v2] Created for blocks {}-{} ({} blocks, {} chunks, {} slots/round)", - start_height, target_height, target_height - start_height + 1, - total_chunks_, slots_per_round_); -} - -block_download_coordinator_v2::~block_download_coordinator_v2() { - stop(); -} - -// ============================================================================= -// Peer Interface (Lock-Free) -// ============================================================================= - -std::optional block_download_coordinator_v2::claim_chunk() { - if (stopped_.load(std::memory_order_acquire) || failed_.load(std::memory_order_acquire)) { - return std::nullopt; - } - - // Wait if round is being reset - while (resetting_.load(std::memory_order_acquire)) { - std::this_thread::yield(); - } - - uint32_t r = round_.load(std::memory_order_acquire); - - // Search for a FREE slot - for (size_t i = 0; i < slots_per_round_; ++i) { - uint8_t expected = FREE; - if (slots_[i].compare_exchange_strong(expected, IN_PROGRESS, - std::memory_order_acq_rel, std::memory_order_relaxed)) { - // Got slot i - slot_times_[i].store(now_ms(), std::memory_order_release); - - uint32_t chunk_id = r * slots_per_round_ + i; - - // Check if this chunk is beyond our target - auto [block_start, block_end] = chunk_range(chunk_id); - if (block_start > target_height_) { - // No more chunks needed - mark as completed and return nullopt - slots_[i].store(COMPLETED, std::memory_order_release); - return std::nullopt; - } - - spdlog::debug("[coordinator_v2] Claimed chunk {} (slot {}, round {}, blocks {}-{})", - chunk_id, i, r, block_start, block_end); - - return chunk_id; - } - } - - // All slots occupied - try to advance round - // First check if all are COMPLETED - bool all_completed = true; - for (size_t i = 0; i < slots_per_round_; ++i) { - if (slots_[i].load(std::memory_order_acquire) != COMPLETED) { - all_completed = false; - break; - } - } - - if (all_completed) { - try_advance_round(); - // Retry claim after round advance - return claim_chunk(); - } - - // Some slots are IN_PROGRESS - wait for them or timeout will reset them - spdlog::debug("[coordinator_v2] All slots occupied, waiting..."); - return std::nullopt; -} - -std::pair block_download_coordinator_v2::chunk_range(uint32_t chunk_id) const { - uint32_t block_start = start_height_ + chunk_id * config_.chunk_size; - uint32_t block_end = std::min(block_start + static_cast(config_.chunk_size) - 1, target_height_); - return {block_start, block_end}; -} - -hash_digest block_download_coordinator_v2::get_block_hash(uint32_t height) const { - return organizer_.index().get_hash(static_cast(height)); -} - -void block_download_coordinator_v2::chunk_completed(uint32_t chunk_id) { - uint32_t r = chunk_id / slots_per_round_; - size_t slot = chunk_id % slots_per_round_; - - uint32_t current_round = round_.load(std::memory_order_acquire); - if (r != current_round) { - // Old round - ignore - spdlog::debug("[coordinator_v2] Chunk {} completed but from old round {} (current: {})", - chunk_id, r, current_round); - return; - } - - // Mark as completed - slots_[slot].store(COMPLETED, std::memory_order_release); - chunks_completed_.fetch_add(1, std::memory_order_relaxed); - - spdlog::debug("[coordinator_v2] Chunk {} completed (slot {})", chunk_id, slot); - - // Try to advance round if all completed - try_advance_round(); -} - -void block_download_coordinator_v2::chunk_failed(uint32_t chunk_id) { - uint32_t r = chunk_id / slots_per_round_; - size_t slot = chunk_id % slots_per_round_; - - uint32_t current_round = round_.load(std::memory_order_acquire); - if (r != current_round) { - // Old round - ignore - return; - } - - // Reset to FREE so another peer can take it - uint8_t expected = IN_PROGRESS; - if (slots_[slot].compare_exchange_strong(expected, FREE, - std::memory_order_acq_rel, std::memory_order_relaxed)) { - spdlog::info("[coordinator_v2] Chunk {} failed, reset to FREE", chunk_id); - } -} - -// ============================================================================= -// Block Reception & Validation -// ============================================================================= - -void block_download_coordinator_v2::block_received(uint32_t height, block_const_ptr block) { - std::lock_guard lock(validation_mutex_); - - if (stopped_ || failed_) { - return; - } - - // Store in pending buffer - pending_blocks_[height] = std::move(block); - - spdlog::trace("[coordinator_v2] Block {} received, {} pending, next to validate: {}", - height, pending_blocks_.size(), next_height_to_validate_); - - // Try to push ready blocks to validation - flush_pending_to_validation(); -} - -::asio::awaitable>> -block_download_coordinator_v2::next_block_to_validate() -{ - if (stopped_ || failed_) { - co_return std::nullopt; - } - - auto [ec, block_pair] = co_await validation_queue_->async_receive( - ::asio::as_tuple(::asio::use_awaitable)); - - if (ec) { - co_return std::nullopt; - } - - co_return block_pair; -} - -void block_download_coordinator_v2::validation_complete(uint32_t height, code result) { - if (result != error::success) { - spdlog::error("[coordinator_v2] Validation failed at height {}: {}", - height, result.message()); - set_failed(result); - return; - } - - uint32_t validated = blocks_validated_.fetch_add(1, std::memory_order_relaxed) + 1; - - // Check if we're done - if (validated >= (target_height_ - start_height_ + 1)) { - spdlog::info("[coordinator_v2] All {} blocks validated", - target_height_ - start_height_ + 1); - validation_queue_->close(); - } -} - -// ============================================================================= -// Status & Control -// ============================================================================= - -void block_download_coordinator_v2::check_timeouts() { - if (stopped_ || failed_) { - return; - } - - uint64_t now = now_ms(); - uint64_t timeout_ms = std::chrono::duration_cast( - config_.stall_timeout).count(); - - for (size_t i = 0; i < slots_per_round_; ++i) { - if (slots_[i].load(std::memory_order_acquire) == IN_PROGRESS) { - uint64_t assigned_at = slot_times_[i].load(std::memory_order_acquire); - if (assigned_at > 0 && (now - assigned_at) > timeout_ms) { - // Slot stalled - reset to FREE - uint8_t expected = IN_PROGRESS; - if (slots_[i].compare_exchange_strong(expected, FREE, - std::memory_order_acq_rel, std::memory_order_relaxed)) { - uint32_t chunk_id = round_.load(std::memory_order_acquire) * slots_per_round_ + i; - spdlog::warn("[coordinator_v2] Chunk {} (slot {}) timed out, reset to FREE", - chunk_id, i); - } - } - } - } -} - -bool block_download_coordinator_v2::is_complete() const { - auto validated = blocks_validated_.load(std::memory_order_acquire); - auto total = target_height_ - start_height_ + 1; - bool complete = validated >= total; - if (complete) { - spdlog::info("[coordinator_v2] is_complete() = true: validated={}, total={}, start={}, target={}", - validated, total, start_height_, target_height_); - } - return complete; -} - -bool block_download_coordinator_v2::has_failed() const { - return failed_.load(std::memory_order_acquire); -} - -bool block_download_coordinator_v2::is_stopped() const { - return stopped_.load(std::memory_order_acquire); -} - -code block_download_coordinator_v2::failure_reason() const { - return failure_reason_; -} - -void block_download_coordinator_v2::stop() { - if (stopped_.exchange(true, std::memory_order_acq_rel)) { - return; - } - - if (validation_queue_) { - validation_queue_->close(); - } -} - -void block_download_coordinator_v2::peer_started() { - spdlog::info("[coordinator_v2] peer_started() called on coordinator at {}", static_cast(this)); - auto prev = active_peers_.fetch_add(1, std::memory_order_relaxed); - spdlog::info("[coordinator_v2] peer_started() completed, was {}, now {}", prev, prev + 1); -} - -void block_download_coordinator_v2::peer_stopped() { - active_peers_.fetch_sub(1, std::memory_order_relaxed); -} - -block_download_coordinator_v2::progress block_download_coordinator_v2::get_progress() const { - // Count assigned and completed slots in current round - uint32_t in_progress = 0; - uint32_t completed = 0; - for (size_t i = 0; i < slots_per_round_; ++i) { - uint8_t state = slots_[i].load(std::memory_order_acquire); - if (state == IN_PROGRESS) ++in_progress; - else if (state == COMPLETED) ++completed; - } - - // Get pending blocks count - uint32_t pending = 0; - { - std::lock_guard lock(const_cast(validation_mutex_)); - pending = static_cast(pending_blocks_.size()); - } - - return { - .chunks_assigned = in_progress + completed, - .chunks_completed = chunks_completed_.load(std::memory_order_acquire), - .chunks_in_progress = in_progress, - .blocks_validated = blocks_validated_.load(std::memory_order_acquire), - .blocks_pending = pending, - .current_round = round_.load(std::memory_order_acquire), - .start_height = start_height_, - .target_height = target_height_, - .active_peers = active_peers_.load(std::memory_order_acquire), - .start_time = start_time_ - }; -} - -// ============================================================================= -// Private Helpers -// ============================================================================= - -void block_download_coordinator_v2::try_advance_round() { - // Check if all slots are COMPLETED - for (size_t i = 0; i < slots_per_round_; ++i) { - if (slots_[i].load(std::memory_order_acquire) != COMPLETED) { - return; // Not all completed - } - } - - // All completed - try to acquire reset lock - bool expected = false; - if (!resetting_.compare_exchange_strong(expected, true, - std::memory_order_acq_rel, std::memory_order_relaxed)) { - return; // Another thread is resetting - } - - // We have the reset lock - uint32_t old_round = round_.load(std::memory_order_acquire); - uint32_t new_round = old_round + 1; - - // Check if we've processed all chunks - uint32_t chunks_in_new_round = new_round * slots_per_round_; - if (chunks_in_new_round >= total_chunks_) { - // All chunks assigned - no need to advance, sync is almost done - resetting_.store(false, std::memory_order_release); - return; - } - - spdlog::info("[coordinator_v2] Advancing to round {} (chunks {}-{})", - new_round, chunks_in_new_round, chunks_in_new_round + slots_per_round_ - 1); - - // Reset all slots to FREE - for (size_t i = 0; i < slots_per_round_; ++i) { - slots_[i].store(FREE, std::memory_order_relaxed); - slot_times_[i].store(0, std::memory_order_relaxed); - } - - // Advance round counter - round_.store(new_round, std::memory_order_release); - - // Release reset lock - resetting_.store(false, std::memory_order_release); -} - -void block_download_coordinator_v2::flush_pending_to_validation() { - // Must be called with validation_mutex_ held - - while (!pending_blocks_.empty()) { - auto it = pending_blocks_.find(next_height_to_validate_); - if (it == pending_blocks_.end()) { - break; // Next block not yet received - } - - auto block_pair = std::make_pair(next_height_to_validate_, it->second); - - bool sent = validation_queue_->try_send(std::error_code{}, std::move(block_pair)); - if (!sent) { - // Channel full - try again later - break; - } - - pending_blocks_.erase(it); - ++next_height_to_validate_; - } -} - -void block_download_coordinator_v2::set_failed(code reason) { - if (failed_.exchange(true, std::memory_order_acq_rel)) { - return; - } - - failure_reason_ = reason; - spdlog::error("[coordinator_v2] Sync failed: {}", reason.message()); - - if (validation_queue_) { - validation_queue_->close(); - } -} - -uint64_t block_download_coordinator_v2::now_ms() { - return static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch() - ).count() - ); -} - -} // namespace kth::node diff --git a/src/node/src/executor/executor.cpp b/src/node/src/executor/executor.cpp index 21817481..76704801 100644 --- a/src/node/src/executor/executor.cpp +++ b/src/node/src/executor/executor.cpp @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -45,437 +45,285 @@ using std::error_code; using kth::database::data_base; using std::placeholders::_1; +// static auto const application_name = "kth"; +static constexpr int initialize_stop = 0; static constexpr int directory_exists = 0; static constexpr int directory_not_found = 2; static auto const mode = std::ofstream::out | std::ofstream::app; -// ============================================================================= -// Construction / Destruction -// ============================================================================= +std::promise executor::stopping_; //NOLINT -executor::executor(kth::node::configuration const& config, bool stdout_enabled) +executor::executor(kth::node::configuration const& config, bool stdout_enabled /*= true*/) : stdout_enabled_(stdout_enabled) , config_(config) { #if ! defined(__EMSCRIPTEN__) - auto const& network = config_.network; - kth::log::initialize(network.debug_file.string(), network.error_file.string(), stdout_enabled, network.verbose); -#endif // ! defined(__EMSCRIPTEN__) -} + auto& network = config_.network; + auto const verbose = network.verbose; -executor::~executor() { - // Ensure clean shutdown - if (state_.load() == state::running) { - stop(); - } -} - -// ============================================================================= -// IO Thread Management -// ============================================================================= + // Build user agent features list + std::vector features; +#if defined(KTH_CURRENCY_BCH) + features.push_back(format_eb(config_.chain.default_consensus_block_size)); +#endif -void executor::start_io_thread() { - // Create work guard to keep io_context alive even when there's no work - work_guard_.emplace(io_context_.get_executor()); + network.user_agent = get_user_agent(features); - // Start io_context in background thread - io_thread_ = std::thread([this]() { - io_context_.run(); - }); + kth::log::initialize(network.debug_file.string(), network.error_file.string(), stdout_enabled, verbose); +#endif // ! defined(__EMSCRIPTEN__) } -void executor::stop_io_thread() { - spdlog::debug("[executor] stop_io_thread() - releasing work guard..."); - // Release work guard to allow io_context to stop - work_guard_.reset(); - - spdlog::debug("[executor] stop_io_thread() - stopping io_context..."); - // Stop io_context +executor::~executor() { + if (running_) { + signal_stop(); + } + // Ensure io_context is stopped and thread is joined io_context_.stop(); - - spdlog::debug("[executor] stop_io_thread() - joining io thread..."); - // Wait for thread to finish if (io_thread_.joinable()) { io_thread_.join(); } - spdlog::debug("[executor] stop_io_thread() - done"); } -// ============================================================================= -// Async Lifecycle -// ============================================================================= - -void executor::start_async(start_handler handler) { - auto expected = state::stopped; - if (!state_.compare_exchange_strong(expected, state::starting)) { - if (handler) { - handler(error::operation_failed); // Already started/starting/stopping - } - return; - } - - // Initialize the run_completed promise/future pair for this run - run_completed_promise_ = std::promise(); - run_completed_future_ = run_completed_promise_.get_future(); - - // Initialize output and directory - initialize_output("", config_.database.db_mode); - - spdlog::info("[node] Press CTRL-C to stop the node."); - spdlog::info("[node] Please wait while the node is starting..."); +void executor::print_version(std::string_view extra) { + std::println(KTH_VERSION_MESSAGE, kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); +} #if ! defined(KTH_DB_READONLY) - auto ec = init_directory_if_necessary(); - if (ec != error::success) { - auto const& directory = config_.database.directory; - spdlog::error("[node] Failed to create directory {} with error, '{}'.", directory.string(), ec.message()); - if (handler) { - handler(ec); - } - return; - } -#endif - - // Create the node - node_ = std::make_shared(config_); - - // Start IO thread - start_io_thread(); - - // Spawn the startup coroutine - ::asio::co_spawn(io_context_, [this, handler]() -> ::asio::awaitable { - // Start the node - auto start_ec = co_await node_->start(); - if (start_ec != error::success) { - spdlog::error("[node] Node failed to start with error: {}.", start_ec.message()); - if (handler) { - handler(start_ec); - } - // Notify sync version - { - std::lock_guard lock(start_mutex_); - start_result_ = start_ec; - } - start_cv_.notify_all(); - // Signal run completed (early exit) so stop() doesn't hang - run_completed_promise_.set_value(); - co_return; - } - - spdlog::info("[node] Seeding is complete."); - - // Mark as running BEFORE calling run() so start() can return - // run() blocks until the node is stopped, so we must notify first - state_ = state::running; +// TODO(fernando): This function inserts the genesis block directly into the DB, +// bypassing the blockchain layer (header_organizer/block_chain). When we implement +// persistence for header_index, we should reconsider this design - ideally genesis +// should be added through the same path as other headers for consistency. +bool executor::init_directory(error_code& ec) { + auto const& directory = config_.database.directory; - // Notify handler - if (handler) { - handler(error::success); - } + if (create_directories(directory, ec)) { + spdlog::info("[node] {}", fmt::format(KTH_INITIALIZING_CHAIN, directory.string())); - // Notify sync version so start() can return - { - std::lock_guard lock(start_mutex_); - start_result_ = error::success; - } - start_cv_.notify_all(); + auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); + auto const& settings = config_.database; - spdlog::info("[node] Node is started."); + data_base db(settings); + auto const result = db.create(genesis); - // Run the node (starts P2P, sync, etc.) - // This blocks until the node is stopped (via stop()) - auto run_ec = co_await node_->run(); - if (run_ec != error::success && run_ec != error::service_stopped) { - spdlog::error("[node] Node run ended with error: {}.", run_ec.message()); + if ( ! result ) { + spdlog::info("[node] {}", KTH_INITCHAIN_FAILED); + return false; } - spdlog::debug("[node] Node run() completed, signaling run_completed_promise."); - - // Signal that run() has completed - stop() waits for this before destroying the node - run_completed_promise_.set_value(); - - }, [this, handler](std::exception_ptr ep) { - if (ep) { - try { - std::rethrow_exception(ep); - } catch (std::exception const& e) { - spdlog::error("[node] Startup exception: {}", e.what()); - } - if (handler) { - handler(error::operation_failed); - } - // Notify sync version - { - std::lock_guard lock(start_mutex_); - start_result_ = error::operation_failed; - } - start_cv_.notify_all(); + spdlog::info("[node] {}", KTH_INITCHAIN_COMPLETE); + return true; + } - // Signal run completed (with error) so stop() doesn't hang - run_completed_promise_.set_value(); - } - }); + return false; } -void executor::stop_async(stop_handler handler) { - auto expected = state::running; - if (!state_.compare_exchange_strong(expected, state::stopping)) { - // Not running or already stopping - if (handler) { - handler(); - } - return; - } +// CAPI +bool executor::do_initchain(std::string_view extra) { + initialize_output(extra, config_.database.db_mode); - spdlog::info("[node] Please wait while the node is stopping..."); + error_code ec; - // Stop node - if (node_) { - node_->stop(); + if (init_directory(ec)) { + return true; } - // Cleanup must happen on a separate thread to avoid blocking io_context. - // The cleanup thread waits for run() to complete before calling join(). - std::thread cleanup_thread([this, handler]() { - // CRITICAL: Wait for run() to fully complete before cleanup. - // run() may still be inside chain.organize() when stop() is called. - // We must wait for all coroutines to exit before destroying resources. - spdlog::debug("[executor] Waiting for run() to complete..."); - if (run_completed_future_.valid()) { - run_completed_future_.wait(); - } - spdlog::debug("[executor] run() completed, proceeding with cleanup"); - - // Now it's safe to join (all coroutines have exited) - if (node_) { - node_->join(); - } - - spdlog::info("[node] Node stopped successfully."); - spdlog::info("[node] Good bye!"); - - state_ = state::stopped; - - // Handler MUST be called LAST - caller may destroy objects after this - if (handler) { - handler(); - } - }); - cleanup_thread.detach(); -} - -// ============================================================================= -// Sync Lifecycle -// ============================================================================= - -code executor::start() { - std::unique_lock lock(start_mutex_); - - // Start async - start_async(nullptr); + auto const& directory = config_.database.directory; - // Wait for completion with periodic wakeup - // This allows external signal handlers to interrupt us - while (!start_cv_.wait_for(lock, std::chrono::milliseconds(100), [this]() { - return state_.load() == state::running || start_result_ != error::success; - })) { - // Check if we should abort (e.g., signal received) - // The caller can check g_signal_received after start() returns + if (ec.value() == directory_exists) { + spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_EXISTS, directory.string())); + return false; } - return start_result_; + spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); + return false; } -void executor::stop() { - if (state_.load() != state::running) { - return; - } - - std::promise done_promise; - auto done_future = done_promise.get_future(); +#endif // ! defined(KTH_DB_READONLY) - stop_async([&done_promise]() { - done_promise.set_value(); - }); +kth::node::full_node& executor::node() { + return *node_; +} - // Wait for stop_async's cleanup coroutine to complete - done_future.wait(); +kth::node::full_node const& executor::node() const { + return *node_; +} - spdlog::debug("[executor] stop() - cleanup coroutine completed, waiting for run() to complete..."); +// Close must be called from main thread. +bool executor::close() { + spdlog::info("[node] {}", KTH_NODE_STOPPING); - // CRITICAL: Wait for run() coroutine to fully complete before destroying the node. - // This ensures all parallel_sync and other coroutines have finished and won't - // access destroyed objects. Without this, we get segfaults on shutdown. - if (run_completed_future_.valid()) { - run_completed_future_.wait(); + if (node_) { + node_->stop(); + node_->join(); + spdlog::info("[node] {}", KTH_NODE_STOPPED); } - spdlog::debug("[executor] stop() - run() completed, destroying node..."); - - // Destroy node BEFORE stopping io_context - // (node's components use io_context for timer cancellation, etc.) - node_.reset(); - - spdlog::debug("[executor] stop() - node destroyed, stopping io thread..."); - - // Stop IO thread - stop_io_thread(); + // Stop the io_context and wait for the io thread to finish + io_context_.stop(); + if (io_thread_.joinable()) { + io_thread_.join(); + } - spdlog::debug("[executor] stop() - io thread stopped, exiting stop()"); + spdlog::info("[node] {}", KTH_GOOD_BYE); + running_ = false; + return true; } -// Global variable for signal handling (required for std::signal) -namespace { - std::atomic g_signal_received{0}; - std::atomic g_signal_waiting{false}; - - void signal_handler(int signal_number) { - // Immediate print to stderr (unbuffered) so user sees it right away - // Note: fprintf is async-signal-safe, std::println is not - // std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); - // std::fflush(stderr); - g_signal_received.store(signal_number); - } +// private +bool executor::wait_for_signal_and_close() { + // Wait for stop. Ensure calling close from the main thread. + stopping_.get_future().wait(); + return close(); } -void executor::wait_for_stop_signal() { - // Mark that we're waiting for a signal - g_signal_waiting.store(true); - - // Install signal handlers using std::signal (simpler and more reliable) - auto prev_sigint = std::signal(SIGINT, signal_handler); - auto prev_sigterm = std::signal(SIGTERM, signal_handler); - - // Poll for signal (simple and reliable) - while (g_signal_received.load() == 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - auto signal_received = g_signal_received.load(); - spdlog::info("[node] Stop signal detected (code: {}).", signal_received); +#if ! defined(KTH_DB_READONLY) - // Restore previous handlers - std::signal(SIGINT, prev_sigint); - std::signal(SIGTERM, prev_sigterm); - g_signal_waiting.store(false); -} +error_code executor::init_directory_if_necessary() { + if (verify_directory()) return error::success; -// ============================================================================= -// State -// ============================================================================= + error_code ec; + if (init_directory(ec)) return error::success; -bool executor::running() const { - return state_.load() == state::running; + return ec; } -bool executor::started() const { - auto s = state_.load(); - return s == state::starting || s == state::running || s == state::stopping; -} +// Helper to run node in coroutine context +void executor::run_node_async(start_modules mod) { + ::asio::co_spawn(io_context_, [this, mod]() -> ::asio::awaitable { + // Start the node + auto start_ec = co_await node_->start(); + if (start_ec != error::success) { + spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, start_ec.message())); + if (run_handler_) { + run_handler_(start_ec); + } + co_return; + } -bool executor::stopped() const { - return state_.load() == state::stopped; -} + spdlog::info("[node] {}", KTH_NODE_SEEDED); + + // Run the node (only for full mode, not just_chain) + if (mod != start_modules::just_chain) { + auto run_ec = co_await node_->run(); + if (run_ec != error::success) { + spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, run_ec.message())); + if (run_handler_) { + run_handler_(run_ec); + } + co_return; + } + } -// ============================================================================= -// Node Access -// ============================================================================= + spdlog::info("[node] {}", KTH_NODE_STARTED); -kth::node::full_node& executor::node() { - return *node_; -} + if (run_handler_) { + run_handler_(error::success); + } + }, ::asio::detached); -kth::node::full_node const& executor::node() const { - return *node_; + // Run the io_context in a background thread (saved for proper shutdown) + io_thread_ = std::thread([this]() { + io_context_.run(); + }); } -// ============================================================================= -// Initialization Helpers -// ============================================================================= - -#if ! defined(KTH_DB_READONLY) -bool executor::init_directory(error_code& ec) { - auto const& directory = config_.database.directory; +bool executor::init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler) { + run_handler_ = std::move(handler); - if (create_directories(directory, ec)) { - spdlog::info("[node] Please wait while initializing {} directory...", directory.string()); + initialize_output(extra, config_.database.db_mode); - auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); - auto const& settings = config_.database; + spdlog::info("[node] {}", KTH_NODE_INTERRUPT); + spdlog::info("[node] {}", KTH_NODE_STARTING); - data_base db(settings); - auto const result = db.create(genesis); + auto ec = init_directory_if_necessary(); + if (ec != error::success) { + auto const& directory = config_.database.directory; + spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); - if (!result) { - spdlog::info("[node] Error creating database files."); - return false; + if (run_handler_) { + run_handler_(ec); } - - spdlog::info("[node] Completed initialization."); - return true; + auto res = wait_for_signal_and_close(); + return false; } - return false; + // Now that the directory is verified we can create the node for it. + node_ = std::make_shared(config_); + running_ = true; + + // Start and run the node asynchronously + run_node_async(mod); + + auto res = wait_for_signal_and_close(); + return res; } -bool executor::do_initchain(std::string_view extra) { - initialize_output(extra, config_.database.db_mode); +bool executor::init_run(std::string_view extra, start_modules mod, kth::handle0 handler) { + run_handler_ = std::move(handler); - error_code ec; + initialize_output(extra, config_.database.db_mode); - if (init_directory(ec)) { - return true; - } + spdlog::info("[node] {}", KTH_NODE_INTERRUPT); + spdlog::info("[node] {}", KTH_NODE_STARTING); - auto const& directory = config_.database.directory; + auto ec = init_directory_if_necessary(); + if (ec != error::success) { + auto const& directory = config_.database.directory; + spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); - if (ec.value() == directory_exists) { - spdlog::error("[node] Failed because the directory {} already exists.", directory.string()); + if (run_handler_) { + run_handler_(ec); + } return false; } - spdlog::error("[node] Failed to create directory {} with error, '{}'.", directory.string(), ec.message()); - return false; -} - -error_code executor::init_directory_if_necessary() { - if (verify_directory()) return error::success; + // Now that the directory is verified we can create the node for it. + node_ = std::make_shared(config_); + running_ = true; - error_code ec; - if (init_directory(ec)) return error::success; + // Start and run the node asynchronously + run_node_async(mod); - return ec; + return true; } + #endif // ! defined(KTH_DB_READONLY) -bool executor::verify_directory() { - error_code ec; - auto const& directory = config_.database.directory; +bool executor::stopped() const { + return node_ ? node_->stopped() : true; +} - if (exists(directory, ec)) { - return true; - } +// Stop signal. +// ---------------------------------------------------------------------------- - if (ec.value() == directory_not_found) { - spdlog::error("[node] The {} directory is not initialized, run: kth --initchain", directory.string()); - return false; +void executor::handle_stop(int code) { + // Reinitialize after each capture to prevent hard shutdown. + // Do not capture failure signals as calling stop can cause flush lock file + // to clear due to the aborted thread dropping the flush lock mutex. + std::signal(SIGINT, handle_stop); + std::signal(SIGTERM, handle_stop); + + if (code == initialize_stop) { + return; } - auto const message = ec.message(); - spdlog::error("[node] Failed to test directory {} with error, '{}'.", directory.string(), message); - return false; + spdlog::info("[node] {}", fmt::format(KTH_NODE_SIGNALED, code)); + stop(kth::error::success); } -void executor::print_version(std::string_view extra) { -#ifdef NDEBUG - std::println("Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}", - kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); -#else - std::println("Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}\n (Debug Build)", - kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); -#endif +void executor::signal_stop() { + stop(kth::code()); +} + +// Manage the race between console stop and server stop. +void executor::stop(kth::code const& ec) { + static std::once_flag stop_mutex; + std::call_once(stop_mutex, [&](){ stopping_.set_value(ec); }); } +// Utilities. +// ---------------------------------------------------------------------------- + void executor::print_ascii_art() { std::print(R"( ... .-=*#%%= :-=+++*#: @@ -496,6 +344,7 @@ void executor::print_ascii_art() { High Performance Bitcoin Cash Node )"); + // Center version under the slogan constexpr char slogan[] = "High Performance Bitcoin Cash Node"; constexpr auto slogan_start = 10; auto version_text = std::format("v{}", kth::version); @@ -504,6 +353,7 @@ void executor::print_ascii_art() { std::println(); } +// Set up logging. void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { auto const& file = config_.file; @@ -512,9 +362,9 @@ void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { } if (file.empty()) { - spdlog::info("[node] Using default configuration settings."); + spdlog::info("[node] {}", KTH_USING_DEFAULT_CONFIG); } else { - spdlog::info("[node] Using config file: {}", file.string()); + spdlog::info("[node] {}", fmt::format(KTH_USING_CONFIG_FILE, file.string())); } std::string_view db_type_str; @@ -526,21 +376,38 @@ void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { db_type_str = KTH_DB_TYPE_PRUNED; } - spdlog::info("[node] Knuth v{}", kth::version); - spdlog::info("[node] Currency: {} - {}.", KTH_CURRENCY_SYMBOL_STR, KTH_CURRENCY_STR); - spdlog::info("[node] Optimized for microarchitecture: {}.", KTH_MICROARCHITECTURE_STR); - spdlog::info("[node] Built for CPU instructions/extensions: {}.", march_names()); - spdlog::info("[node] Database type: {}.", db_type_str); + spdlog::info("[node] {}", fmt::format(KTH_VERSION_MESSAGE_INIT, kth::version)); + spdlog::info("[node] {}", fmt::format(KTH_CRYPTOCURRENCY_INIT, KTH_CURRENCY_SYMBOL_STR, KTH_CURRENCY_STR)); + spdlog::info("[node] {}", fmt::format(KTH_MICROARCHITECTURE_INIT, KTH_MICROARCHITECTURE_STR)); + spdlog::info("[node] {}", fmt::format(KTH_MARCH_EXTS_INIT, march_names())); + spdlog::info("[node] {}", fmt::format(KTH_DB_TYPE_INIT, db_type_str)); #ifndef NDEBUG - spdlog::info("[node] (Debug Build)"); + spdlog::info("[node] {}", KTH_DEBUG_BUILD_INIT); #endif - auto const network_id = config_.network.identifier; - auto const network_type = kth::get_network(network_id, config_.network.inbound_port == 48333); - spdlog::info("[node] Network: {0} ({1} - {1:#x}).", name(network_type), network_id); - spdlog::info("[node] Blockchain configured to use {} threads.", kth::thread_ceiling(config_.chain.cores)); - spdlog::info("[node] Networking configured to use {} threads.", kth::thread_ceiling(config_.network.threads)); + spdlog::info("[node] {}", fmt::format(KTH_NETWORK_INIT, name(kth::get_network(config_.network.identifier, config_.network.inbound_port == 48333)), config_.network.identifier)); + spdlog::info("[node] {}", fmt::format(KTH_BLOCKCHAIN_CORES_INIT, kth::thread_ceiling(config_.chain.cores))); + spdlog::info("[node] {}", fmt::format(KTH_NETWORK_CORES_INIT, kth::thread_ceiling(config_.network.threads))); +} + +// Use missing directory as a sentinel indicating lack of initialization. +bool executor::verify_directory() { + error_code ec; + auto const& directory = config_.database.directory; + + if (exists(directory, ec)) { + return true; + } + + if (ec.value() == directory_not_found) { + spdlog::error("[node] {}", fmt::format(KTH_UNINITIALIZED_CHAIN, directory.string())); + return false; + } + + auto const message = ec.message(); + spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_TRY, directory.string(), message)); + return false; } } // namespace kth::node diff --git a/src/node/src/full_node.cpp b/src/node/src/full_node.cpp index 543bd3dd..2d207ea2 100644 --- a/src/node/src/full_node.cpp +++ b/src/node/src/full_node.cpp @@ -13,20 +13,17 @@ #include #include #include -#include #include #include #include #include -#include namespace kth::node { using namespace kth::blockchain; using namespace kth::domain::chain; using namespace kth::domain::config; -using namespace ::asio::experimental::awaitable_operators; #if ! defined(__EMSCRIPTEN__) using namespace kth::network; @@ -43,8 +40,7 @@ full_node::full_node(configuration const& configuration) , chain_settings_(configuration.chain) , network_type_(get_network(configuration.network.identifier, configuration.network.inbound_port == 48333)) , chain_thread_pool_(configuration.chain.cores) - , network_settings_(configuration.network) - , network_(network_settings_) + , network_(configuration.network) , chain_( chain_thread_pool_, configuration.chain, @@ -65,29 +61,11 @@ full_node::full_node(configuration const& configuration) network_type_ ) #endif -{ -#if ! defined(__EMSCRIPTEN__) - spdlog::debug("[full_node] configuration.network.threads = {}", configuration.network.threads); - spdlog::debug("[full_node] network_settings_.threads = {}", network_settings_.threads); - - // Set user agent after initialization (network_ holds reference to network_settings_) - std::vector features; -#if defined(KTH_CURRENCY_BCH) - features.push_back(format_eb(configuration.chain.default_consensus_block_size)); -#endif - network_settings_.user_agent = get_user_agent(features); -#endif -} +{} full_node::~full_node() { - spdlog::debug("[full_node] destructor starting"); - // Only stop/join if not already stopped - if (!stopped()) { - spdlog::debug("[full_node] destructor - not stopped, calling stop/join"); - stop(); - join(); - } - spdlog::debug("[full_node] destructor - about to destroy members"); + stop(); + join(); } // ============================================================================= @@ -148,144 +126,90 @@ ::asio::awaitable full_node::run() { spdlog::info("[node] Node start heights: header-sync ({}), block-sync ({}).", header_height, block_height); -#if ! defined(__EMSCRIPTEN__) - // Run all background tasks in parallel using structured concurrency. - // This blocks until ALL tasks complete (i.e., until stop() is called). - // No detached coroutines - everything is properly awaited. - spdlog::debug("[full_node] Starting parallel tasks with && operator"); - co_await ( - run_blockchain_subscriber() && - network_.run() && - run_sync() - ); - spdlog::debug("[full_node] All parallel tasks completed"); -#else - // WASM: only blockchain subscriber (no network) - co_await run_blockchain_subscriber(); -#endif - - co_return error::success; -} - -::asio::awaitable full_node::run_blockchain_subscriber() { - spdlog::debug("[full_node] run_blockchain_subscriber() starting"); + // Subscribe to blockchain reorganizations auto blockchain_channel = subscribe_blockchain(); - if (!blockchain_channel) { - spdlog::debug("[full_node] run_blockchain_subscriber() - no channel, exiting"); - co_return; - } - spdlog::debug("[full_node] run_blockchain_subscriber() - channel obtained, entering loop"); - - auto executor = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(executor); - - while (!stopped()) { - // Non-blocking try_receive - size_t fork_height{}; - block_const_ptr_list_const_ptr incoming{}; - block_const_ptr_list_const_ptr outgoing{}; - - bool received = blockchain_channel->try_receive([&](std::error_code ec, size_t fh, auto in, auto out) { - if (!ec) { - fork_height = fh; - incoming = std::move(in); - outgoing = std::move(out); - } - }); - - if (received) { - if (!handle_reorganized(error::success, fork_height, incoming, outgoing)) { - unsubscribe_blockchain(blockchain_channel); - break; - } - } else if (!blockchain_channel->is_open()) { - // Channel closed - break; - } else { - // No data, sleep briefly - timer.expires_after(std::chrono::milliseconds(100)); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - break; // Timer cancelled + if (blockchain_channel) { + ::asio::co_spawn(chain_.executor(), [this, blockchain_channel]() -> ::asio::awaitable { + while (blockchain_channel->is_open() && !stopped()) { + auto result = co_await blockchain_channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + auto& [ec, fork_height, incoming, outgoing] = result; + + if (ec) { + break; + } + + if ( ! handle_reorganized(error::success, fork_height, incoming, outgoing)) { + unsubscribe_blockchain(blockchain_channel); + break; + } } - } + }, ::asio::detached); } - spdlog::debug("[full_node] run_blockchain_subscriber() exiting"); -} #if ! defined(__EMSCRIPTEN__) -::asio::awaitable full_node::run_sync() { - spdlog::debug("[full_node] run_sync() starting"); - auto executor = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(executor); - - while (!stopped()) { - // Wait until we have at least one connected peer - while (!stopped() && network_.connection_count() == 0) { - timer.expires_after(std::chrono::milliseconds(100)); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec || stopped()) { - spdlog::debug("[full_node] run_sync() exiting"); - co_return; - } - } - - if (stopped()) { - co_return; - } - - spdlog::info("[node] Starting initial block sync..."); - auto result = co_await sync_from_best_peer(chain_, network_, network_type_); - - if (stopped()) { - co_return; - } - - if (result.error) { - spdlog::warn("[node] Sync failed: {} (connected peers: {}), retrying...", - result.error.message(), network_.connection_count()); - // Brief delay to allow maintain_outbound_connections to find new peers - timer.expires_after(std::chrono::milliseconds(500)); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec || stopped()) { - co_return; - } - continue; - } - - // Check if we actually synced something - if (result.headers_received > 0 || result.blocks_received > 0) { - spdlog::info("[node] Sync progress: {} headers, {} blocks, height {}", - result.headers_received, result.blocks_received, result.final_height); - // Continue syncing - there might be more blocks - if (stopped()) { - co_return; - } - continue; - } - - // No sync happened - no peers ahead of us - // Wait longer before checking again (allows new peers to connect) - spdlog::debug("[node] No peers ahead of us at height {}, waiting for new peers...", - result.final_height); - timer.expires_after(std::chrono::seconds(5)); - auto [ec2] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec2 || stopped()) { - break; // Timer cancelled or stop requested - } + // Run the P2P network (starts connections and protocol handlers) + auto ec = co_await network_.run(); + if (ec != error::success) { + spdlog::error("[node] Failure running network: {}", ec.message()); + co_return ec; } - spdlog::debug("[full_node] run_sync() exiting"); -} + + // Start sync in background + // TODO(fernando): Make this configurable and add proper sync management + // TODO(fernando): blockchain::block_chain should migrate to coroutines + // (organize, fetch_*, etc.) to eliminate callbacks and std::promise usage + ::asio::co_spawn(network_.thread_pool().get_executor(), + [this]() -> ::asio::awaitable { + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + constexpr auto retry_delay = std::chrono::seconds(10); + + while (!stopped()) { + // Wait until we have at least one connected peer + while (!stopped() && network_.connection_count() == 0) { + timer.expires_after(std::chrono::milliseconds(500)); + co_await timer.async_wait(::asio::use_awaitable); + } + + if (stopped()) { + co_return; + } + + spdlog::info("[node] Starting initial block sync..."); + auto result = co_await sync_from_best_peer(chain_, network_, network_type_); + + if (result.error) { + spdlog::warn("[node] Sync failed: {}, retrying in {}s...", + result.error.message(), retry_delay.count()); + + // Wait before retrying + timer.expires_after(retry_delay); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return; // Timer cancelled, node stopping + } + continue; + } + + spdlog::info("[node] Initial sync complete: {} headers, {} blocks, height {}", + result.headers_received, result.blocks_received, result.final_height); + break; // Sync successful, exit loop + } + }, ::asio::detached); #endif + co_return error::success; +} + void full_node::stop() { #if ! defined(__EMSCRIPTEN__) - // IMPORTANT: Only stop the network here, NOT the chain! - // The chain must remain operational until run() completes because - // run_sync() may still be inside chain.organize() when this is called. - // chain_.stop() is called in join() after run() has fully exited. network_.stop(); #endif + + if (!chain_.stop()) { + spdlog::error("[node] Failed to stop blockchain."); + } } void full_node::join() { @@ -293,12 +217,6 @@ void full_node::join() { network_.join(); #endif - // Now that run() has exited (all coroutines done), it's safe to stop the chain. - // This must happen AFTER run() completes to avoid crashes in chain.organize(). - if (!chain_.stop()) { - spdlog::error("[node] Failed to stop blockchain."); - } - if (!chain_.close()) { spdlog::error("[node] Failed to close blockchain."); } diff --git a/src/node/src/parallel_sync.cpp b/src/node/src/parallel_sync.cpp deleted file mode 100644 index bd6b35af..00000000 --- a/src/node/src/parallel_sync.cpp +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -namespace kth::node { - -namespace { - -// ============================================================================= -// Peer Download Loop -// ============================================================================= - -/// Download loop for a single peer -::asio::awaitable peer_download_loop( - block_download_coordinator& coordinator, - network::peer_session::ptr peer, - parallel_download_config const& config) -{ - auto executor = co_await ::asio::this_coro::executor; - - spdlog::info("[parallel_sync] Download loop STARTED for peer [{}]", - peer->authority()); - - // Check initial conditions - spdlog::debug("[parallel_sync] Peer [{}] - checking initial conditions", peer->authority()); - if (coordinator.is_complete()) { - spdlog::debug("[parallel_sync] Peer [{}] - sync already complete, exiting", - peer->authority()); - co_return; - } - if (coordinator.has_failed()) { - spdlog::debug("[parallel_sync] Peer [{}] - sync already failed, exiting", - peer->authority()); - co_return; - } - if (peer->stopped()) { - spdlog::debug("[parallel_sync] Peer [{}] - peer already stopped, exiting", - peer->authority()); - co_return; - } - - spdlog::debug("[parallel_sync] Peer [{}] - entering main loop", peer->authority()); - while (!coordinator.is_complete() && !coordinator.has_failed() && !peer->stopped()) { - // Claim blocks to download - spdlog::debug("[parallel_sync] Peer [{}] - calling claim_blocks", peer->authority()); - auto blocks = co_await coordinator.claim_blocks(peer, config.max_blocks_per_peer); - spdlog::debug("[parallel_sync] Peer [{}] - claim_blocks returned {} blocks", peer->authority(), blocks.size()); - - if (blocks.empty()) { - // No blocks available - wait a bit and retry - spdlog::debug("[parallel_sync] Peer [{}] - claim_blocks returned empty, waiting 100ms...", - peer->authority()); - ::asio::steady_timer timer(executor); - timer.expires_after(std::chrono::milliseconds(100)); - co_await timer.async_wait(::asio::use_awaitable); - continue; - } - - spdlog::info("[parallel_sync] Peer [{}] CLAIMED {} blocks ({}-{}), requesting...", - peer->authority(), blocks.size(), blocks.front().first, blocks.back().first); - - // Request all blocks in ONE getdata message (batch mode) - // This is MUCH faster than requesting one block at a time - auto batch_result = co_await network::request_blocks_batch(*peer, blocks, config.block_timeout); - - if (!batch_result) { - spdlog::warn("[parallel_sync] Failed to get blocks from peer [{}]: {}", - peer->authority(), batch_result.error().message()); - co_await coordinator.peer_disconnected(peer); - // Stop the peer so network can drop it and connect to new peers - peer->stop(batch_result.error()); - co_return; - } - - spdlog::debug("[parallel_sync] Peer [{}] received {} blocks, reporting to coordinator", - peer->authority(), batch_result->size()); - - // Report all received blocks to coordinator - for (auto& block_with_h : *batch_result) { - auto block_ptr = std::make_shared(std::move(block_with_h.block)); - // Get the original hash from the blocks vector - auto it = std::find_if(blocks.begin(), blocks.end(), - [h = block_with_h.height](auto const& p) { return p.first == h; }); - if (it != blocks.end()) { - co_await coordinator.block_received(block_with_h.height, it->second, block_ptr); - } - } - - } - - // Log why we exited - if (coordinator.is_complete()) { - spdlog::debug("[parallel_sync] Peer [{}] - exiting: sync complete", peer->authority()); - } else if (coordinator.has_failed()) { - spdlog::debug("[parallel_sync] Peer [{}] - exiting: sync failed", peer->authority()); - } else if (peer->stopped()) { - spdlog::debug("[parallel_sync] Peer [{}] - exiting: peer stopped", peer->authority()); - } else { - spdlog::debug("[parallel_sync] Peer [{}] - exiting: unknown reason", peer->authority()); - } -} - -// ============================================================================= -// Validation Pipeline -// ============================================================================= - -/// Validation pipeline - validates blocks in order -::asio::awaitable validation_pipeline( - block_download_coordinator& coordinator, - blockchain::block_chain& chain) -{ - spdlog::debug("[parallel_sync] Starting validation pipeline"); - - while (true) { - // Get next block to validate (blocks until available) - auto block_opt = co_await coordinator.next_block_to_validate(); - - if (!block_opt) { - // No more blocks or sync failed - break; - } - - auto const& [height, block] = *block_opt; - - spdlog::trace("[parallel_sync] Validating block at height {}", height); - - // Validate and store block - // Note: organize() validates the block and adds it to the chain. - // headers_pre_validated=true because this is headers-first sync. - auto result = co_await chain.organize(block, /*headers_pre_validated=*/true); - - coordinator.validation_complete(height, result); - - if (result != error::success) { - spdlog::error("[parallel_sync] Block validation failed at height {}: {}", - height, result.message()); - break; - } - - // Log progress periodically - if (height % 1000 == 0) { - auto progress = coordinator.get_progress(); - auto now = std::chrono::steady_clock::now(); - auto elapsed_secs = std::chrono::duration_cast( - now - progress.start_time).count(); - - // Calculate speed and ETA - double blocks_per_sec = elapsed_secs > 0 - ? static_cast(progress.blocks_validated) / static_cast(elapsed_secs) - : 0.0; - - uint32_t total_blocks = progress.target_height - progress.start_height + 1; - uint32_t remaining = total_blocks - progress.blocks_validated; - uint32_t eta_secs = blocks_per_sec > 0 - ? static_cast(static_cast(remaining) / blocks_per_sec) - : 0; - - // Format ETA as HH:MM:SS - uint32_t eta_hours = eta_secs / 3600; - uint32_t eta_mins = (eta_secs % 3600) / 60; - uint32_t eta_s = eta_secs % 60; - - double percent = 100.0 * static_cast(progress.blocks_validated) / - static_cast(total_blocks); - - spdlog::info("[parallel_sync] Height: {} ({:.1f}%) | {:.0f} blk/s | ETA: {:02d}:{:02d}:{:02d} | peers: {} | in-flight: {}", - height, percent, blocks_per_sec, eta_hours, eta_mins, eta_s, - progress.active_peers, progress.blocks_in_flight); - } - } - - spdlog::debug("[parallel_sync] Validation pipeline completed"); -} - -// ============================================================================= -// Timeout Checker -// ============================================================================= - -/// Periodically check for stalled downloads -::asio::awaitable timeout_checker( - block_download_coordinator& coordinator, - parallel_download_config const& config) -{ - auto executor = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(executor); - - spdlog::debug("[parallel_sync] Starting timeout checker"); - - while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped()) { - timer.expires_after(config.timeout_check_interval); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - break; // Timer cancelled - } - - coordinator.check_timeouts(); - } - - spdlog::debug("[parallel_sync] Timeout checker completed"); -} - -} // anonymous namespace - -// ============================================================================= -// Main Parallel Sync Function -// ============================================================================= - -::asio::awaitable parallel_block_sync( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - network::p2p_node& network, - uint32_t start_height, - uint32_t target_height, - parallel_download_config const& config) -{ - auto executor = co_await ::asio::this_coro::executor; - - spdlog::info("[parallel_sync] Starting parallel block sync from {} to {} ({} blocks)", - start_height, target_height, target_height - start_height + 1); - - // Create coordinator - block_download_coordinator coordinator( - chain, organizer, start_height, target_height, executor, config); - - // Get available peers (async version) - auto peers = co_await network.peers().all(); - if (peers.empty()) { - spdlog::error("[parallel_sync] No peers available for block download"); - co_return parallel_sync_result{ - .error = error::channel_stopped, - .blocks_downloaded = 0, - .blocks_validated = 0, - .final_height = start_height - }; - } - - spdlog::info("[parallel_sync] Using {} peers for parallel download", peers.size()); - - // ========================================================================= - // Structured concurrency with proper shutdown handling: - // - Download loops run in their own group - // - When ALL download loops exit (peers disconnect or sync complete), - // we stop the coordinator to unblock validation/timeout tasks - // ========================================================================= - - kth::task_group all_tasks(executor); - - // Spawn a "download supervisor" that: - // 1. Runs all download loops in a nested task group - // 2. Watches for new peers and adds them dynamically - // 3. When ALL download loops exit, stops the coordinator - all_tasks.spawn([&]() -> ::asio::awaitable { - kth::task_group download_tasks(executor); - - // Track which peers already have download loops (by address string) - boost::unordered_flat_set active_peers; - - // Start initial peers - for (auto const& peer : peers) { - auto addr = peer->authority().to_string(); - active_peers.insert(addr); - spdlog::info("[parallel_sync] Starting download loop for initial peer [{}]", addr); - download_tasks.spawn(peer_download_loop(coordinator, peer, config)); - } - - // Spawn a peer watcher that adds new peers as they connect - download_tasks.spawn([&]() -> ::asio::awaitable { - auto exec = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(exec); - - while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped() && !network.stopped()) { - timer.expires_after(std::chrono::seconds(2)); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - break; // Timer cancelled - } - - // Check if network is stopping - if (network.stopped()) { - spdlog::debug("[parallel_sync] Peer watcher - network stopped, exiting"); - break; - } - - // Check for new peers and clean up dead ones - auto current_peers = co_await network.peers().all(); - - // Build set of currently connected (live) peer addresses - boost::unordered_flat_set live_addrs; - for (auto const& peer : current_peers) { - if (!peer->stopped()) { - live_addrs.insert(peer->authority().to_string()); - } - } - - // Remove dead peers from active_peers so they can reconnect - erase_if(active_peers, [&live_addrs](auto const& addr) { - return !live_addrs.contains(addr); - }); - - // Add new peers - for (auto const& peer : current_peers) { - if (peer->stopped()) { - continue; - } - auto addr = peer->authority().to_string(); - auto [it, inserted] = active_peers.insert(addr); - if (inserted) { - spdlog::debug("[parallel_sync] Spawning download loop for new peer [{}]", addr); - download_tasks.spawn(peer_download_loop(coordinator, peer, config)); - spdlog::info("[parallel_sync] Added new peer [{}] to download pool (total: {})", - addr, active_peers.size()); - } - } - } - spdlog::debug("[parallel_sync] Peer watcher exiting"); - }()); - - // Wait for all download loops to complete - co_await download_tasks.join(); - - // All downloads done - stop coordinator to unblock validation pipeline - spdlog::debug("[parallel_sync] All download loops exited, stopping coordinator"); - coordinator.stop(); - }()); - - // Spawn validation pipeline - all_tasks.spawn(validation_pipeline(coordinator, chain)); - - // Spawn timeout checker - all_tasks.spawn(timeout_checker(coordinator, config)); - - // Wait for all tasks to complete - co_await all_tasks.join(); - - // Build result - auto progress = coordinator.get_progress(); - parallel_sync_result result{ - .error = coordinator.has_failed() ? coordinator.failure_reason() : error::success, - .blocks_downloaded = progress.blocks_downloaded, - .blocks_validated = progress.blocks_validated, - .final_height = start_height + progress.blocks_validated - 1 - }; - - if (coordinator.is_complete()) { - spdlog::info("[parallel_sync] Parallel sync completed: {} blocks validated", - progress.blocks_validated); - } else if (coordinator.has_failed()) { - spdlog::error("[parallel_sync] Parallel sync failed: {}", - coordinator.failure_reason().message()); - } else { - spdlog::warn("[parallel_sync] Parallel sync interrupted: {} blocks validated", - progress.blocks_validated); - } - - co_return result; -} - -} // namespace kth::node diff --git a/src/node/src/parallel_sync_v2.cpp b/src/node/src/parallel_sync_v2.cpp deleted file mode 100644 index cd7e46a7..00000000 --- a/src/node/src/parallel_sync_v2.cpp +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (c) 2016-2025 Knuth Project developers. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -namespace kth::node { - -namespace { - -// ============================================================================= -// Peer Download Loop (Lock-Free) -// ============================================================================= - -::asio::awaitable peer_download_loop_v2( - block_download_coordinator_v2& coordinator, - network::peer_session::ptr peer, - parallel_download_config_v2 config) // Pass by value to ensure lifetime -{ - spdlog::info("[parallel_sync_v2] Download loop ENTERING for peer [{}], coordinator at {}", - peer->authority(), static_cast(&coordinator)); - - auto executor = co_await ::asio::this_coro::executor; - - spdlog::info("[parallel_sync_v2] Download loop got executor for peer [{}], coordinator at {}", - peer->authority(), static_cast(&coordinator)); - - coordinator.peer_started(); - spdlog::info("[parallel_sync_v2] Download loop STARTED for peer [{}] (active peers: {})", - peer->authority(), coordinator.get_progress().active_peers); - - // RAII guard to decrement peer count on exit - struct peer_guard { - block_download_coordinator_v2& coord; - std::string addr; - ~peer_guard() { - coord.peer_stopped(); - spdlog::info("[parallel_sync_v2] Download loop ENDED for peer [{}] (active peers: {})", - addr, coord.get_progress().active_peers); - } - } guard{coordinator, peer->authority().to_string()}; - - while (!coordinator.is_complete() && !coordinator.has_failed() && !peer->stopped()) { - // Claim a chunk (lock-free!) - auto chunk_opt = coordinator.claim_chunk(); - - if (!chunk_opt) { - // No chunks available - wait a bit and retry - spdlog::debug("[parallel_sync_v2] Peer [{}] - no chunks available, waiting...", - peer->authority()); - ::asio::steady_timer timer(executor); - timer.expires_after(std::chrono::milliseconds(100)); - co_await timer.async_wait(::asio::use_awaitable); - continue; - } - - uint32_t chunk_id = *chunk_opt; - auto [block_start, block_end] = coordinator.chunk_range(chunk_id); - - spdlog::debug("[parallel_sync_v2] Peer [{}] claimed chunk {} (blocks {}-{})", - peer->authority(), chunk_id, block_start, block_end); - - // Build block request list - std::vector> blocks; - for (uint32_t h = block_start; h <= block_end; ++h) { - auto hash = coordinator.get_block_hash(h); - if (hash == null_hash) { - spdlog::error("[parallel_sync_v2] No hash for height {}", h); - coordinator.chunk_failed(chunk_id); - continue; - } - blocks.emplace_back(h, hash); - } - - if (blocks.empty()) { - coordinator.chunk_completed(chunk_id); - continue; - } - - // Request blocks from peer - auto batch_result = co_await network::request_blocks_batch( - *peer, blocks, config.stall_timeout); - - if (!batch_result) { - spdlog::warn("[parallel_sync_v2] Failed to get blocks from peer [{}]: {}", - peer->authority(), batch_result.error().message()); - coordinator.chunk_failed(chunk_id); - peer->stop(batch_result.error()); - co_return; - } - - spdlog::debug("[parallel_sync_v2] Peer [{}] received {} blocks for chunk {}", - peer->authority(), batch_result->size(), chunk_id); - - // Report received blocks - for (auto& block_with_h : *batch_result) { - auto block_ptr = std::make_shared( - std::move(block_with_h.block)); - coordinator.block_received(block_with_h.height, block_ptr); - } - - // Mark chunk as completed - coordinator.chunk_completed(chunk_id); - } - // peer_guard destructor will log exit and decrement peer count -} - -// ============================================================================= -// Validation Pipeline -// ============================================================================= - -::asio::awaitable validation_pipeline_v2( - block_download_coordinator_v2& coordinator, - blockchain::block_chain& chain) -{ - spdlog::debug("[parallel_sync_v2] Starting validation pipeline"); - - while (true) { - auto block_opt = co_await coordinator.next_block_to_validate(); - - if (!block_opt) { - break; - } - - auto const& [height, block] = *block_opt; - - spdlog::trace("[parallel_sync_v2] Validating block at height {}", height); - - auto result = co_await chain.organize(block, /*headers_pre_validated=*/true); - - coordinator.validation_complete(height, result); - - if (result != error::success) { - spdlog::error("[parallel_sync_v2] Block validation failed at height {}: {}", - height, result.message()); - break; - } - - // Log progress periodically - if (height % 1000 == 0) { - auto progress = coordinator.get_progress(); - auto now = std::chrono::steady_clock::now(); - auto elapsed_secs = std::chrono::duration_cast( - now - progress.start_time).count(); - - double blocks_per_sec = elapsed_secs > 0 - ? static_cast(progress.blocks_validated) / static_cast(elapsed_secs) - : 0.0; - - uint32_t total_blocks = progress.target_height - progress.start_height + 1; - uint32_t remaining = total_blocks - progress.blocks_validated; - uint32_t eta_secs = blocks_per_sec > 0 - ? static_cast(static_cast(remaining) / blocks_per_sec) - : 0; - - uint32_t eta_hours = eta_secs / 3600; - uint32_t eta_mins = (eta_secs % 3600) / 60; - uint32_t eta_s = eta_secs % 60; - - double percent = 100.0 * static_cast(progress.blocks_validated) / - static_cast(total_blocks); - - spdlog::info("[parallel_sync_v2] Height: {} ({:.1f}%) | {:.0f} blk/s | ETA: {:02d}:{:02d}:{:02d} | peers: {} | in-flight: {} | pending: {}", - height, percent, blocks_per_sec, eta_hours, eta_mins, eta_s, - progress.active_peers, progress.chunks_in_progress, progress.blocks_pending); - } - } - - spdlog::debug("[parallel_sync_v2] Validation pipeline completed"); -} - -// ============================================================================= -// Timeout Checker -// ============================================================================= - -::asio::awaitable timeout_checker_v2( - block_download_coordinator_v2& coordinator, - parallel_download_config_v2 const& config) -{ - auto executor = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(executor); - - spdlog::debug("[parallel_sync_v2] Starting timeout checker"); - - while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped()) { - timer.expires_after(config.timeout_check_interval); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - break; - } - - coordinator.check_timeouts(); - } - - spdlog::debug("[parallel_sync_v2] Timeout checker completed"); -} - -} // anonymous namespace - -// ============================================================================= -// Main Parallel Sync V2 Function -// ============================================================================= - -::asio::awaitable parallel_block_sync_v2( - blockchain::block_chain& chain, - blockchain::header_organizer& organizer, - network::p2p_node& network, - uint32_t start_height, - uint32_t target_height, - parallel_download_config_v2 const& config) -{ - auto executor = co_await ::asio::this_coro::executor; - - spdlog::info("[parallel_sync_v2] Starting parallel block sync from {} to {} ({} blocks)", - start_height, target_height, target_height - start_height + 1); - - // Create coordinator - block_download_coordinator_v2 coordinator( - chain, organizer, start_height, target_height, executor, config); - - spdlog::info("[parallel_sync_v2] Coordinator created at address {}", static_cast(&coordinator)); - - // Get available peers - auto peers = co_await network.peers().all(); - if (peers.empty()) { - spdlog::error("[parallel_sync_v2] No peers available for block download"); - co_return parallel_sync_result_v2{ - .error = error::channel_stopped, - .blocks_downloaded = 0, - .blocks_validated = 0, - .final_height = start_height - }; - } - - spdlog::info("[parallel_sync_v2] Using {} peers for parallel download", peers.size()); - - kth::task_group all_tasks(executor); - - // Spawn download supervisor - all_tasks.spawn([&]() -> ::asio::awaitable { - kth::task_group download_tasks(executor); - - boost::unordered_flat_set active_peers; - - // Start initial peers - for (auto const& peer : peers) { - auto addr = peer->authority().to_string(); - active_peers.insert(addr); - spdlog::info("[parallel_sync_v2] Starting download loop for initial peer [{}]", addr); - download_tasks.spawn(peer_download_loop_v2(coordinator, peer, config)); - } - - // Peer watcher - monitors for new peer connections and adds them to download pool - download_tasks.spawn([&]() -> ::asio::awaitable { - auto exec = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(exec); - - spdlog::info("[parallel_sync_v2] Peer watcher STARTED"); - - while (true) { - // Check exit conditions with logging - if (coordinator.is_complete()) { - spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator complete"); - break; - } - if (coordinator.has_failed()) { - spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator failed"); - break; - } - if (coordinator.is_stopped()) { - spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator stopped"); - break; - } - if (network.stopped()) { - spdlog::info("[parallel_sync_v2] Peer watcher exiting: network stopped"); - break; - } - - timer.expires_after(std::chrono::seconds(2)); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - spdlog::info("[parallel_sync_v2] Peer watcher exiting: timer cancelled (ec={})", ec.message()); - break; - } - - auto current_peers = co_await network.peers().all(); - - boost::unordered_flat_set live_addrs; - size_t stopped_count = 0; - for (auto const& peer : current_peers) { - if (!peer->stopped()) { - live_addrs.insert(peer->authority().to_string()); - } else { - ++stopped_count; - } - } - - spdlog::info("[parallel_sync_v2] Peer watcher check: {} total, {} live, {} stopped, {} tracked", - current_peers.size(), live_addrs.size(), stopped_count, active_peers.size()); - - // Remove disconnected peers from tracking - auto removed = erase_if(active_peers, [&live_addrs](auto const& addr) { - return !live_addrs.contains(addr); - }); - if (removed > 0) { - spdlog::info("[parallel_sync_v2] Removed {} disconnected peers from tracking", removed); - } - - // Add new peers - for (auto const& peer : current_peers) { - if (peer->stopped()) continue; - auto addr = peer->authority().to_string(); - auto [it, inserted] = active_peers.insert(addr); - if (inserted) { - spdlog::info("[parallel_sync_v2] Adding new peer [{}] to download pool (tracked: {})", - addr, active_peers.size()); - try { - download_tasks.spawn(peer_download_loop_v2(coordinator, peer, config)); - spdlog::info("[parallel_sync_v2] Spawn completed for peer [{}]", addr); - } catch (std::exception const& e) { - spdlog::error("[parallel_sync_v2] Exception spawning peer [{}]: {}", addr, e.what()); - } - } - } - } - }()); - - co_await download_tasks.join(); - - spdlog::debug("[parallel_sync_v2] All download loops exited, stopping coordinator"); - coordinator.stop(); - }()); - - // Spawn validation pipeline - all_tasks.spawn(validation_pipeline_v2(coordinator, chain)); - - // Spawn timeout checker - all_tasks.spawn(timeout_checker_v2(coordinator, config)); - - // Wait for all tasks - co_await all_tasks.join(); - - // Build result - auto progress = coordinator.get_progress(); - parallel_sync_result_v2 result{ - .error = coordinator.has_failed() ? coordinator.failure_reason() : error::success, - .blocks_downloaded = progress.chunks_completed * static_cast(config.chunk_size), - .blocks_validated = progress.blocks_validated, - .final_height = start_height + progress.blocks_validated - 1 - }; - - if (coordinator.is_complete()) { - spdlog::info("[parallel_sync_v2] Parallel sync completed: {} blocks validated", - progress.blocks_validated); - } else if (coordinator.has_failed()) { - spdlog::error("[parallel_sync_v2] Parallel sync failed: {}", - coordinator.failure_reason().message()); - } else { - spdlog::warn("[parallel_sync_v2] Parallel sync interrupted: {} blocks validated", - progress.blocks_validated); - } - - co_return result; -} - -} // namespace kth::node diff --git a/src/node/src/parser.cpp b/src/node/src/parser.cpp index f50911f7..70f250f8 100644 --- a/src/node/src/parser.cpp +++ b/src/node/src/parser.cpp @@ -95,8 +95,8 @@ void parser::set_default_configuration() { // Logs will slow things if not rotated. configured.network.rotation_size = 10000000; - // Headers-first sync allows parallel block downloads from multiple peers. - configured.network.outbound_connections = 8; + // With block-first sync the count should be low until complete. + configured.network.outbound_connections = 2; // A node allows 1000 host names by default. configured.network.host_pool_capacity = 1000; diff --git a/src/node/src/sync_session.cpp b/src/node/src/sync_session.cpp index 884efb1d..167b2bcd 100644 --- a/src/node/src/sync_session.cpp +++ b/src/node/src/sync_session.cpp @@ -9,31 +9,16 @@ #include #include -#include #include -#include #include #include -#include -#include namespace kth::node { using namespace kth::blockchain; using namespace kth::network; -// "Permanent" ban duration - 10 years in seconds -// Using a large but safe value instead of hours::max() to avoid overflow -constexpr auto permanent_ban_duration = std::chrono::seconds(10 * 365 * 24 * 60 * 60); - -// Forward declaration - defined at end of file -static ::asio::awaitable persist_headers_background( - block_chain& chain, - header_index const& index, - size_t start_height, - size_t end_height); - // ============================================================================= // Construction // ============================================================================= @@ -42,13 +27,10 @@ sync_session::sync_session( block_chain& chain, peer_session::ptr peer, domain::config::network network, - sync_config const& config, - size_t target_height, - p2p_node* p2p_node) + sync_config const& config) : chain_(chain) , organizer_(chain.headers(), chain.chain_settings(), network) , peer_(std::move(peer)) - , p2p_node_(p2p_node) , config_(config) { // Get current chain heights (header-sync and block-sync) @@ -58,14 +40,10 @@ sync_session::sync_session( block_height_ = heights->second; // block-sync height } - // Use provided target height if given, otherwise use peer's start_height - if (target_height > 0) { - target_height_ = target_height; - } else { - auto peer_version = peer_->peer_version(); - if (peer_version) { - target_height_ = peer_version->start_height(); - } + // Get target height from peer's version message + auto peer_version = peer_->peer_version(); + if (peer_version) { + target_height_ = peer_version->start_height(); } // Get hash of current header tip (for getheaders locator) @@ -88,11 +66,9 @@ sync_session::ptr make_sync_session( block_chain& chain, peer_session::ptr peer, domain::config::network network, - sync_config const& config, - size_t target_height, - p2p_node* p2p_node) + sync_config const& config) { - return std::make_shared(chain, peer, network, config, target_height, p2p_node); + return std::make_shared(chain, peer, network, config); } // ============================================================================= @@ -103,7 +79,7 @@ ::asio::awaitable sync_session::run() { sync_result result{}; spdlog::info("[sync] Starting headers-first sync with [{}], header-sync: {}, block-sync: {}", - peer_->authority_with_agent(), header_height_, block_height_); + peer_->authority(), header_height_, block_height_); // Check peer version supports headers-first if (peer_->negotiated_version() < config_.minimum_version) { @@ -130,18 +106,18 @@ ::asio::awaitable sync_session::run() { spdlog::info("[sync] Phase 1: Syncing headers from [{}], target height {}, current {}, need ~{} headers", peer_->authority(), target_height_, current_header_height, headers_to_sync); - // // Log memory allocator info - // if (kth::is_jemalloc_active()) { - // spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); - // } else { - // spdlog::info("[sync] Memory allocator: system default"); - // } + // Log memory allocator info + if (kth::is_jemalloc_active()) { + spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); + } else { + spdlog::info("[sync] Memory allocator: system default"); + } // Log system memory info - // auto const total_mem = kth::get_total_system_memory(); - // auto const available_mem = kth::get_available_system_memory(); - // spdlog::info("[sync] System memory: total {} MB, available {} MB", - // total_mem / (1024 * 1024), available_mem / (1024 * 1024)); + auto const total_mem = kth::get_total_system_memory(); + auto const available_mem = kth::get_available_system_memory(); + spdlog::info("[sync] System memory: total {} MB, available {} MB", + total_mem / (1024 * 1024), available_mem / (1024 * 1024)); // BCHN-style: Calculate headers sync deadline // Timeout = base + per_header * expected_headers @@ -163,8 +139,8 @@ ::asio::awaitable sync_session::run() { // spdlog::info("[sync] Header cache: optimal size {} headers", optimal_cache); // Measure memory before sync - // auto const mem_before = kth::get_resident_memory(); - // spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); + auto const mem_before = kth::get_resident_memory(); + spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); auto const start_time = std::chrono::steady_clock::now(); int consecutive_timeouts = 0; @@ -245,24 +221,33 @@ ::asio::awaitable sync_session::run() { } // Measure memory after headers received - // auto const mem_after_headers = kth::get_resident_memory(); - // auto const bytes_per_header = total_headers_ > 0 - // ? (mem_after_headers - mem_before) / total_headers_ : 0; - // spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", - // total_headers_, mem_after_headers / (1024 * 1024), - // (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); - - // NOTE: Header persistence to DB now happens in Phase 2 as a background task - // This allows block sync to proceed immediately while headers are saved + auto const mem_after_headers = kth::get_resident_memory(); + auto const bytes_per_header = total_headers_ > 0 + ? (mem_after_headers - mem_before) / total_headers_ : 0; + spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", + total_headers_, mem_after_headers / (1024 * 1024), + (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); + + // TODO(fernando): implement DB persistence for headers + // For now headers are kept in memory only (header_index) + // if (organizer_.has_pending()) { + // spdlog::info("[sync] Flushing {} cached headers to database...", + // organizer_.cache_size()); + // auto const db_start = std::chrono::steady_clock::now(); + // + // auto const flush_ec = organizer_.flush(); + // if (flush_ec && flush_ec != error::duplicate_block) { + // spdlog::warn("[sync] Failed to flush headers: {}", flush_ec.message()); + // result.error = flush_ec; + // co_return result; + // } + // + // auto const db_elapsed = std::chrono::steady_clock::now() - db_start; + // auto const db_ms = std::chrono::duration_cast(db_elapsed).count(); + // spdlog::info("[sync] Headers flush completed in {}ms", db_ms); + // } auto const final_header_height = organizer_.header_height(); - - // Check why header sync ended - if (!synced_ && peer_->stopped()) { - spdlog::warn("[sync] Header sync peer disconnected at height {} (target was {})", - final_header_height, target_height_); - } - spdlog::info("[sync] Phase 1 complete: synced to height {} ({} new headers) from [{}]", final_header_height, total_headers_, peer_->authority()); @@ -273,93 +258,32 @@ ::asio::awaitable sync_session::run() { } // ========================================================================== - // PHASE 2: Download blocks (with parallel header persistence) + // PHASE 2: Download blocks // ========================================================================== auto const final_header_height = organizer_.header_height(); - - // Spawn background task to persist headers to database - // This runs in parallel with block sync - headers are in memory for block validation - // but also being written to DB so restart won't require re-syncing headers - { - // Get current DB header height to determine what needs persisting - auto const db_heights = chain_.get_last_heights(); - size_t db_header_height = db_heights ? db_heights->first : 0; - - // Only persist if we have new headers beyond what's in DB - if (final_header_height > 0 && size_t(final_header_height) > db_header_height) { - auto executor = co_await ::asio::this_coro::executor; - - // Spawn persist task in background (detached) - // Uses references to chain_ and index which outlive sync_session - ::asio::co_spawn(executor, - persist_headers_background( - chain_, - organizer_.index(), - db_header_height + 1, - static_cast(final_header_height)), - ::asio::detached); - } - } - if (block_height_ < final_header_height) { + // Get block hashes from header_index (not database - headers are in memory) auto const blocks_to_download = final_header_height - block_height_; spdlog::info("[sync] Phase 2: Need to download {} blocks ({} to {})", blocks_to_download, block_height_ + 1, final_header_height); - // Use parallel block sync if p2p_node is available - if (p2p_node_ != nullptr) { - spdlog::info("[sync] Phase 2: Using parallel block download from multiple peers"); - - // Convert sync_config to parallel_download_config_v2 (lock-free coordinator) - parallel_download_config_v2 parallel_config{ - .chunk_size = 16, // Blocks per chunk (Bitcoin protocol limit) - .slots_multiplier = 100, // slots_per_round = max_peers * 100 - .max_peers = 8, - .stall_timeout = std::chrono::seconds(config_.block_stalling_timeout), - .timeout_check_interval = std::chrono::seconds(5) - }; - - auto parallel_result = co_await parallel_block_sync_v2( - chain_, - organizer_, - *p2p_node_, - static_cast(block_height_ + 1), - static_cast(final_header_height), - parallel_config); - - if (parallel_result.error) { - spdlog::error("[sync] Parallel block sync failed: {}", - parallel_result.error.message()); - result.error = parallel_result.error; - co_return result; - } - - total_blocks_ = parallel_result.blocks_validated; - block_height_ = parallel_result.final_height; - - spdlog::info("[sync] Phase 2 complete: {} blocks validated via parallel sync", - parallel_result.blocks_validated); - - } else { - // Fallback to sequential download from single peer - spdlog::info("[sync] Phase 2: Using sequential block download from [{}]", - peer_->authority()); + std::vector block_hashes; + block_hashes.reserve(blocks_to_download); - std::vector block_hashes; - block_hashes.reserve(blocks_to_download); + // During IBD, headers are added in order, so index == height for main chain + auto& idx = organizer_.index(); + for (size_t h = block_height_ + 1; h <= size_t(final_header_height); ++h) { + block_hashes.push_back(idx.get_hash(h)); + } - // During IBD, headers are added in order, so index == height for main chain - auto& idx = organizer_.index(); - for (size_t h = block_height_ + 1; h <= size_t(final_header_height); ++h) { - block_hashes.push_back(idx.get_hash(h)); - } + spdlog::info("[sync] Phase 2: Downloading {} blocks from [{}]", + block_hashes.size(), peer_->authority()); - auto ec = co_await sync_blocks(block_hashes); - if (ec) { - result.error = ec; - co_return result; - } + auto ec = co_await sync_blocks(block_hashes); + if (ec) { + result.error = ec; + co_return result; } } @@ -669,28 +593,12 @@ ::asio::awaitable sync_from_best_peer( { sync_result result{}; - // Get current chain heights - use header index for sync selection - // During headers-first sync, header index > persisted headers > blocks + // Get current chain heights size_t our_block_height = 0; - size_t our_db_header_height = 0; auto const heights = chain.get_last_heights(); if (heights) { - our_db_header_height = heights->first; our_block_height = heights->second; } - // Header index may have more headers than persisted to DB - size_t our_header_height = chain.headers().size(); - if (our_header_height > 0) { - --our_header_height; // size() is count, height is count-1 - } - - // For peer selection: - // - If we need blocks (block_height < header_height), use block_height - // so we select peers that can give us blocks - // - If headers and blocks are synced, use header_height for new blocks - size_t our_sync_height = (our_block_height < our_header_height) - ? our_block_height // Need blocks - select peers ahead of our block height - : std::max({our_header_height, our_db_header_height, our_block_height}); // BCHN-style: don't wait for minimum peers, start sync immediately // when any suitable peer is available @@ -704,31 +612,6 @@ ::asio::awaitable sync_from_best_peer( co_return result; } - // Peers below max checkpoint are useless for sync - auto const max_checkpoint_height = chain.chain_settings().max_checkpoint_height; - - // Filter out peers below max checkpoint - auto const initial_peer_count = peers.size(); - peers.erase( - std::remove_if(peers.begin(), peers.end(), - [max_checkpoint_height](auto const& peer) { - auto version = peer->peer_version(); - return !version || size_t(version->start_height()) < max_checkpoint_height; - }), - peers.end()); - - if (peers.empty()) { - spdlog::warn("[sync] No peers at or above checkpoint height {} (filtered {} peers)", - max_checkpoint_height, initial_peer_count); - result.error = error::channel_stopped; - co_return result; - } - - if (peers.size() < initial_peer_count) { - spdlog::debug("[sync] Filtered {} peers below checkpoint height {}", - initial_peer_count - peers.size(), max_checkpoint_height); - } - // Count peers by type for logging size_t preferred_count = 0; size_t full_node_count = 0; @@ -741,51 +624,28 @@ ::asio::awaitable sync_from_best_peer( } } - // Calculate max height across all peers (BCHN-style) - // Don't trust just one peer's reported height - size_t max_peer_height = 0; - for (auto const& peer : peers) { - auto version = peer->peer_version(); - if (version) { - max_peer_height = std::max(max_peer_height, size_t(version->start_height())); - } - } - - spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), " - "our height: {} (headers: {}, blocks: {}), checkpoint: {}, max peer: {}", - peers.size(), preferred_count, full_node_count, - our_sync_height, our_header_height, our_block_height, max_checkpoint_height, max_peer_height); + spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), our height: {}", + peers.size(), preferred_count, full_node_count, our_block_height); // Select best peer using BCHN logic - auto best_peer = select_sync_peer(peers, our_sync_height); + auto best_peer = select_sync_peer(peers, our_block_height); if (!best_peer) { - // Check if there are peers with higher height that we couldn't sync from - // (e.g., all were banned or filtered out) - if (max_peer_height > our_sync_height) { - spdlog::info("[sync] No suitable peers found among {} remaining (none ahead of height {})", - peers.size(), our_sync_height); - result.error = error::operation_failed; - result.final_height = our_sync_height; - co_return result; - } - // Truly synced - no peers have higher height - spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_sync_height); + spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_block_height); result.error = error::success; - result.final_height = our_sync_height; + result.final_height = our_block_height; co_return result; } auto version = best_peer->peer_version(); auto const best_height = version ? version->start_height() : 0; - spdlog::info("[sync] Selected {} peer [{}] with height {} for sync (target: {})", + spdlog::info("[sync] Selected {} peer [{}] with height {} for sync", best_peer->is_preferred_download() ? "preferred" : "fallback", - best_peer->authority_with_agent(), best_height, max_peer_height); + best_peer->authority(), best_height); - // Run sync with selected peer, using max_peer_height as target - // Pass p2p_node to enable parallel block download - auto session = make_sync_session(chain, best_peer, network, config, max_peer_height, &p2p); + // Run sync with selected peer + auto session = make_sync_session(chain, best_peer, network, config); result = co_await session->run(); // BCHN-style: If sync failed (including timeout), try another peer @@ -793,23 +653,18 @@ ::asio::awaitable sync_from_best_peer( if (result.error) { if (result.timed_out) { spdlog::warn("[sync] Peer [{}] timed out (too slow), disconnecting and trying another...", - best_peer->authority_with_agent()); + best_peer->authority()); // BCHN disconnects slow peers best_peer->stop(error::channel_timeout); } else if (result.error == error::checkpoints_failed) { // BCHN bans peers that send headers failing checkpoint validation // This typically indicates a peer on a different chain (BSV, etc.) - spdlog::warn("[sync] Peer [{}] sent headers failing checkpoint (wrong chain?), banning permanently...", - best_peer->authority_with_agent()); - p2p.ban_peer(best_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); - } else if (result.error == error::store_block_missing_parent) { - // Headers don't connect to our chain - peer is likely on a different chain - spdlog::warn("[sync] Peer [{}] sent headers that don't connect (wrong chain?), banning permanently...", - best_peer->authority_with_agent()); - p2p.ban_peer(best_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + spdlog::warn("[sync] Peer [{}] sent headers failing checkpoint (wrong chain?), banning...", + best_peer->authority()); + p2p.ban_peer(best_peer, std::chrono::hours{24}, network::ban_reason::checkpoint_failed); } else { spdlog::warn("[sync] Sync with [{}] failed: {}, trying another peer...", - best_peer->authority_with_agent(), result.error.message()); + best_peer->authority(), result.error.message()); } // Remove failed peer from consideration and try again @@ -817,27 +672,23 @@ ::asio::awaitable sync_from_best_peer( std::remove(peers.begin(), peers.end(), best_peer), peers.end()); - spdlog::debug("[sync] {} peers remaining after removing failed peer", peers.size()); - // Retry with remaining peers until we succeed or run out of peers int retry = 0; while (!peers.empty()) { - auto retry_peer = select_sync_peer(peers, our_sync_height); + auto retry_peer = select_sync_peer(peers, our_block_height); if (!retry_peer) { - spdlog::info("[sync] No suitable peers found among {} remaining (none ahead of height {})", - peers.size(), our_sync_height); break; } ++retry; version = retry_peer->peer_version(); auto const retry_height = version ? version->start_height() : 0; - spdlog::info("[sync] Retry {}: {} peer [{}] height {} (target: {})", + spdlog::info("[sync] Retry {}: {} peer [{}] height {}", retry, retry_peer->is_preferred_download() ? "preferred" : "fallback", - retry_peer->authority_with_agent(), retry_height, max_peer_height); + retry_peer->authority(), retry_height); - auto retry_session = make_sync_session(chain, retry_peer, network, config, max_peer_height, &p2p); + auto retry_session = make_sync_session(chain, retry_peer, network, config); result = co_await retry_session->run(); if (!result.error) { @@ -846,18 +697,13 @@ ::asio::awaitable sync_from_best_peer( if (result.timed_out) { spdlog::warn("[sync] Retry peer [{}] timed out, disconnecting...", - retry_peer->authority_with_agent()); + retry_peer->authority()); retry_peer->stop(error::channel_timeout); } else if (result.error == error::checkpoints_failed) { // Ban peers that fail checkpoint (wrong chain) - spdlog::warn("[sync] Retry peer [{}] sent headers failing checkpoint (wrong chain?), banning permanently...", - retry_peer->authority_with_agent()); - p2p.ban_peer(retry_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); - } else if (result.error == error::store_block_missing_parent) { - // Headers don't connect - wrong chain - spdlog::warn("[sync] Retry peer [{}] sent headers that don't connect (wrong chain?), banning permanently...", - retry_peer->authority_with_agent()); - p2p.ban_peer(retry_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + spdlog::warn("[sync] Retry peer [{}] sent headers failing checkpoint (wrong chain?), banning...", + retry_peer->authority()); + p2p.ban_peer(retry_peer, std::chrono::hours{24}, network::ban_reason::checkpoint_failed); } // Remove this peer and try next @@ -870,80 +716,4 @@ ::asio::awaitable sync_from_best_peer( co_return result; } -// ============================================================================= -// Header Persistence (Background Task) -// ============================================================================= - -// Free function for header persistence - captures only what it needs -// so it can safely run after sync_session is destroyed -static ::asio::awaitable persist_headers_background( - block_chain& chain, - header_index const& index, - size_t start_height, - size_t end_height) -{ - if (start_height > end_height) { - spdlog::debug("[sync] No headers to persist (start {} > end {})", start_height, end_height); - co_return; - } - - auto const total_to_persist = end_height - start_height + 1; - spdlog::info("[sync] Starting background header persistence: {} headers ({} to {})", - total_to_persist, start_height, end_height); - - auto const persist_start = std::chrono::steady_clock::now(); - - // Persist in batches to avoid holding large vectors in memory - constexpr size_t batch_size = 1000; - - size_t persisted = 0; - size_t height = start_height; - - while (height <= end_height) { - // Build batch of headers - domain::chain::header::list batch; - auto const batch_end = std::min(height + batch_size - 1, end_height); - batch.reserve(batch_end - height + 1); - - for (size_t h = height; h <= batch_end; ++h) { - // During IBD, index == height (headers added in order) - batch.push_back(index.get_header(static_cast(h))); - } - - // Persist batch to database - auto const ec = chain.organize_headers_batch(batch, height); - if (ec) { - spdlog::warn("[sync] Header persistence failed at height {}: {}", - height, ec.message()); - // Don't abort - headers are still in memory for block sync - co_return; - } - - persisted += batch.size(); - height = batch_end + 1; - - // Log progress every 50000 headers - if (persisted % 50000 < batch_size) { - auto const elapsed = std::chrono::steady_clock::now() - persist_start; - auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); - auto const rate = elapsed_secs > 0 ? persisted / elapsed_secs : persisted; - spdlog::info("[sync] Header persistence progress: {}/{} ({}/s)", - persisted, total_to_persist, rate); - } - - // Yield to allow other coroutines to run - co_await ::asio::post(co_await ::asio::this_coro::executor, ::asio::use_awaitable); - } - - auto const elapsed = std::chrono::steady_clock::now() - persist_start; - auto const elapsed_ms = std::chrono::duration_cast(elapsed).count(); - spdlog::info("[sync] Header persistence complete: {} headers in {}ms", - persisted, elapsed_ms); -} - -// Member function wrapper (for declaration compatibility) -::asio::awaitable sync_session::persist_headers_to_db(size_t start_height, size_t end_height) { - co_await persist_headers_background(chain_, organizer_.index(), start_height, end_height); -} - } // namespace kth::node diff --git a/tui_screenshot.png b/tui_screenshot.png deleted file mode 100644 index cdefa169ed42cc29283e5062aa5ef616bb41fcd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1232582 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%0A)MV@E7;M-<5kHP<)ZqGUn7s`AAag9n{bmg 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

23+R!HZAc6UrgF@%%FskNR@qO<=kF{DOpnO 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

ff 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�I~CbarWLpP3>*ls9O|71VpM-0R^Q+q_?2bRGM_87wKJEfRKnN zy@*JWD!q4*PH3U`j&wrrgwR7c3-^A$Iq%GS&OH13JCn?0tzWtC>%Pj%*&(r=8fCg~ zHLYxu=P^t__Aizt<9z__eb_0R*y@dFViszEcAJs6x_={@QcI7S0o#J-+^c2?6-ks_ zY&Iudmz$G(P(TlNN*20U)-s4>lSFItdC5`vGr2kHc;2t>(xvf{OCXBY~N{Qx1(rH_YLzXk1jAAPwKb?%D`_l%6A2MDq--sU6$wXXSM3uKF`I=z8G_nYf-FNlf z(?>Pm35@eX`n`uIrgpzp@35X4hK|1*ck`Hc)!aPnw&6QjKAc)~jZW6B15sIurkGA` zyDN~kT4X*GC6tVbFje*6T+kPP}s(ig=zqiKmmOuQ+| zwc&Z3ptt95wvF>DV!>vK{S(vSPeg9S)8nF_<)@vMC8EKXr%2y#Z6hFS4+x1~L0RAL zrc=J^)BVWBL66=)D31}&^rrsR}xIh?M zF_s`ehqqj`LN$4xY%7jD4V%j@Xs)>#!L2TWf7!*>Gig)&IqUa+mgdHj--EtBB(|f# zPcy|g7X4_)kH+ab{P;Ct zi+VNtwGF$x!oRTN6;D~}G4X5CGjG8AJ0l#uj%k-)EIR7Xu$_W$mQQBV-ITV~+PnvE zsVb2N%d8J^7ADE3f0&8U`_PHOph&e|2+ig@*uvlqH3nwO!rqT)2`zsud=DHqOpdTq zOY#sG`~U~{Pd=3d%Dhn;wq8e+lS8@397d0w2yE*txsXJUFolbGBAHlW{rl}$z+z-MfjvyOT4$qS+56wpQ=CZc& z?c;kBXBtbFz8MCs3f2z(q$J&+-l>gObJjr*xvU84 z5T3YA(PTaZC-U4x4@~&pS9oUS@V?@1@chDolQns~>gwTPyt0_}>6u+~fp}%&;>D5C zAx_J{Dnr=E?4|wZT4(HMe#<=r4Lb6;=SpIS>DaLQZet?rKznIp&g6EMV-?<1Yd%w0 zyPLQ}<8Hy{Wx+!N*dYz&<`sU^3=Vb>r3xOWVBeeeoZ4O&Vow;^DzmcRu%>gjollx( zo}LVS8Rah5KO3JxZ2)z$?gn2YZ4T+_pXlq+Y4&#s87iB=gP67KwLRQdUz zM7YV=ZmQvF%VsupTBV0qiEzZW(%L;4Hi4l@-j}UqtH5}zt6%R|ta&Zq`$!P!NmD`= zTpX=m6K#V5BDhTUUljAk6bQ#CLQWp&P|IO*Wjx33dD2sW^vfcC9(`^m3*zV-v?^#l zdF9eV@$(ZPQGmfuZ90qX(~iajAa2ON zUWOZu5>)1&3o2FL$*<(O!g`XpemVBTOsQ8r%a(geXq=j4)=zUlJ+91Rwn7i=Xo$J! zjnIw02e9ki3;vAXqYXSeJLbMBiCpAk`r){|cii3FwF;tJUzwKAJ$CC!hn(0GzX|OD zB>fhXrkm6uY9#pShhrD!=~l0lk%r5Nv$)OS9`}=DOk`xmm=0ek;$rOaPqg|NZslw} zRA@Gv%H^n7*v@oZe`t@4I^B@T+g9UpV(GQjq*?T`=Frz&+=H2?DGx%NrZ#J1LHJ`b#7k%?7s@w z1USU9uNAkzfABOcm0Cj!I``(o_T{hCoLOtux$MH05`2`<*6n+bDcAM%3j3j|Q!P6WHbLHXpn!S}gmscYLd zZCkU)usoHvdyVI*_@s3p%-PLqDnvz+u2<3AWGLm6&{}6`9zN9`#Qs$Qesl_Z^4FtD zukd2Q^gi%98@0ws^Xi+GqSwbjkGP759r?9^|ib!3IKP*U#Ksb z>kl>C9jV{FkH8Fl&&swz2^ zzz0RMPS#d$f+k`yP6XLy$O>EfN-X)|akM$f4W?5dEl}Hkt4kT$&8aSeSkz`6VPOz% zZj@zo+>0O<>*Wa8X!Ij(*5gHz(K(G2L7>%li`9XnB={$EX|SER0{uY3ODNpaYcbwM9WAz&|KJ>%lve5jj1@7snW1jQKxvUu( zqyK}^3)>k7b5`Xkem-s~y7o=kJ~q<9Vq)BIS9d*=cU+bO{7qHI^{^;n*|F&hLl3(kqqMZ_6dEtOV>i)kqDhz5hWfQNf7O2y zLVFwh@aO@<^O$RQ0eg^Uyxb z+n=7b$4$?tcy+G|t~Zn~2F;+i>0LUE*MsunlE12Z+bdp9SG3lHlnhVzd?6C8>w>*W zx`&5v&#NPVae5CEe6iEgXwuIr{u>*& zJ^r)F2B`3&5H4zehf7|T2+fNBDi}FPFTy7L#763@=FkxQ`0sY&-_>d({r&mpct`S4 z7yguzIde?ofQigFYO7j{Rn`fJn2a3w$pSw@QJ<6Tp-lQ=Wd8KGoSM}QWO*C|@R; zTTmEfh(n&FO7d!`yww=&lkU{89IS}_DAG{#1WRWB5=N1=a>s>3G;>nUl`uF0f{`&C zeTaCv3V}wE(lygE%bxxiFQs<+(sHr)@&RJyBn8h`1u{|naIJ!>?PZD@Bes>G#-yMp zLyi07lN#WoL2~N^EtHArVQ^m-YFje7Fl#XV2;`;BnE7Yt0Y~7G?s`#WXkNnt2eJ>g ziDt1l92xGYQk8)^fH%Gq*J zn6;Z6Nc{Z0j_p3O)P67NJiVkc+{V0UQP3)WAqmXC4Tij>rL2-GZ}sMJq$b~K@R`DT zd=%TCC9LN4Q|?@;%EI3%T>qqVDA;1Bze_UZ5aX9D=PUgsps4UL6a#mLC@w0~e*or; za(LYx;=3WB?Sm;^Mz<-`WS4UWR9w^)*j_GK*9P|b**GzmMN+iz^5_0Qa-}eG?Y^Bl za_v^B;VG7ai%^ImHVxfC^QXR>S#)(%sRQA%kmoFjKB~|lk=}Fx(&jIu1~yTVfpN1A zKHcYwpNKALb}Lyqc@zx|Z%xZk>vO?z252=(6-9r*hy!=dhH zkCR?GB*7Efrul!VlW@YnrXE~=QpyoBe)?aG=l=tmHd+MubTw?FkA25Ck7t}c`LBX= zTikc6CNy6eUZbAEf;oByjpd3WHHs_iiUDnO(VjLcs{%TK2!G7(w(vTp|JS|fRUV8yG&JvxVIkgv3!@UK&fE@ragzzEZvEo3!vyYP~5}q zGP1v^qmM6fjeCuf3$^kk7E&6{R4kfZ`$WX`)xg8!jq8m2rX5N;jy>0gjdD86MDuh4 z)f&dJGlNoP&GN?5mQKQU$H0125gsi3#H0>Tl*H>bl!NhKUn!g zADlcuUpxR}1A_(wLJdPvL}4Z+&V;Pmc4nj+qlV5%D@A${nnx!Oy4ual7cb^HnPhE8 z9y3keA7ri}SZTH7W|HN(A?7T*6OQd6+goba@!X4b?&Jx1t8u{V@aVRsnWgGA9+j74 zJyA4wW+*&^c&NhlrFmCX>+FLnFuc77CiX7(7Ob)!z`6(-iJ7~U@3;Y0F&WsdsZyRX z8Lak7To7#O#U42uWUW&!EzohGTe&J^i29=OThWG@bh)`w5>c9unK4zk_!*6qm1Vvn{<&h4!*Ogu`Gm&-+QGu=b-pr|A$1}G}&HrT#Z~1)U?p0w()Njw}`1-xiw~%y54?)Kezm+mPUn@BS^}xU;6LjiUg3ucrK)lk_j#nGBDxu(=Dby0)(3nyrPtnlt&=_7`)HPL6MuK| zY$VORFL}V^i~Y>d62WfhR@CvH`MxK7V|_C8`GJn+&Ep2^6Z3tMLv^TE8_CUgq?Iw)xX?DXHOd&?2dF4x2U{KXz4) z*%@FeMZIU^+1ABY_a>6a=4cJUMD1qm6HMXsqq|TA!u?MuaQHP=k1BOBPqZ2^AqAm9FF*Py`h4&Tn~s?F*)7rA>Wi{R<# z3bZWfI=U@pJH?+JkkmC4TH;3fb`ziScrSD2E!EQTLyCk2=D)ZwWxZ&9LM|cnoB!fs zw}`*CvZxRj<#K#d0vNd4u{jO3-{vfc1_zOA=ycV)&qQeIx>itJ*yIFx9aqs0mmQn0 z?-q?T*Gsf~tX%BM%OaH=K~$Fw?$&c|=-Wjlz_m62wxkmBZN1M_>g;IRtXCV+aZBTc zHRm+$;@2B^mE-$I?n`>iAI594CN zb0eK?LUldtD@}ptMTu8=(lB41POwwY2^XGmT0Lp?N`0JQ(qbjpQCy}2L<(9NO|s?_ zTOHT0Ajq{pEbK3rbVd$+=x(!m$1Hh%O14fqD6Q=$4nFlM-zt?SP;U`O!K?xw4XwmG z#Qh33kG5MZOXuw6+J^;Hnuso>s|`)A;tE4lLyiCDlUypn90D`wrLmL z9EH)mS=C_v*nfexH{MYP3cp>C%~2XP?z+&|DL!WARa;CkaXcf?W}SG&$(}AZu~6P# zXXpsm&@)CRms`R?Ad{ah{&uY)`tfZ%yq|*gU(&0Nkl_j9LV^gwi5N_IHJwdjslC?( z9*@1?!QNfIshkQyb4arCcJ(J{BW<`g_GRYov8&&g5@J%Ke(`(*{ zEsno^?K*}OslB84dM0BaJnNMG0gl71tS7wVI-(z}!VqY_(iK%k=ocxHQ9sgD(a$+5 zhx0|kqc5a_96yJLVMC0lw}V<@L}H$55C{SUlZS0X%0}yq4DQ4crCYL*Nj}}O$E9MY z^Nr6gc^e72eBEYw5fH+yQ3F<(e1J?$_K5OgP?G zfn6L>*@c7!`%U-UVgZpPMu@(6`*#M+OL1^yWe+NdpMIDP-W~bz|qzk2#&)%FIx=X z?EiuV@)zGztvi?iUxEpucSjA|o)-;XNp>%DZhoR3ymd#dls{?eiv z2Qqw%@~ZG7>(3`*%eKFtEYfu6M=~0&wDNw^stXc?2K|b5hOXa#-k(r6pQdKV+v|pz z*f%q14Ko|dv!A3PTQ0~qFB*&_5?^U%R}x7d*3s^2s>!@Nk@Qvjea@cAor7pkN?BC_ zo9t_QcW+aY0KfLM>h7{dfrnr#^(p1y(zQr>z`n4n$nWklJ4kReL!?S3af~Hac)2Z{ z`crYR6VVrgY+eO!7ggj{03K0;tJFbByD35Ex| z4d?cNlTo0D()o2czvBH^d&=35b;eeD#?#sE{pADK_j!T-Dx^VJ;$ZrKp-%)M%IMkg zVm%=Fl51}Mq;}`FlGn1=cE#Yz`ZD68Kx5J(iI;!7Vd^I~$89vZP*GBJjlBT+_WiWs z4f~E0LibhkXr6to6tAPgP_ME3Ss6{W+uuY0bY1f1PKwB{<(Oo8ED9ru5Eox%f@{s& zPw*w9hw`|mC+hmyU^k|j#v1jnXwq|;;P@Js?QaLiGuH8#6LRHW3NyCexZQq5F_>3v zep=H)-9lR2n64JMX+~ja1GAH#vEIa7&;qwMk%n ziJAbaJ4K5meMJ8^9annKj__d++zHYriQB2oQ3+@1Z{p?@zQEjne8ohPM`laoltVtOQ;kx97b5 zhQmW7GJ0B;Ml=3B4xZ=hyCyjh?C@v^m>+RP1^Qf^o7eGX2o>MytRk;<-MQS1eiQbu zMpMbm_`;Bn#43jqq>;Vz=lK4!jAUU!fr6Ir@V6ExDB45sa{Ic zJ|k<~prr;Pr%*!YlZKnx=5(xXm;h|7Zvpt)R##xCNW;lfmXH&tL7{7f)|4bRpCP^P zY{HUn&=>rmwlVEP)<0u8`2@_7sTrUTx?1#(e~PfuG~;C{MyTnMZ~)Qo-&AhgbR-K` z5?r}Q=~GCf74nz7kYT=zu;*V!reO^yZ@*I~q90T9PLQqBP`12EFtF?bdGWG4L&=s+ zc%as5;v#!Znj@Sf49x*bq?(?KpJnjEtf`~pJ~V#^@KSShM_M@Vcebds#4bsnM-Bsl zx;1lj25-DH5BTl^ud3#NM8zbA9~F9kz1;Y4%B7ExtKQ50u0ysTejlsCJQ=i@kYQP@UzO!SG#S)0&Ury{;G_)q~%oG$fx zb87^k9j-6DKF;JBOn*=fbiu>S{xXrTh^zu;+?2s*Z*{D59+jE3C%VhK&pA5~6?J{M z>JX$NcL?>svm8uL+Y8|RHD9asjOeZ=vF%dbn$4Xf#~kXOuD~ZTmAbpWDh@X*>pj_L z`M?FGU0ouVIZpRltek}djsF??l2h_8k&E{2F5yStM!3s4zaGC`yANv5(9-(>Q$!}`BUBkX0 ze5yDQq>VjE0k7L(>O(R zwUOB5@3Jo08h^tz_4N$xl~U$3N&7=fZ`K)e4dmY-aL}G>=S`Cbnr>;Y&5}K^O{dBY zK9AhGmotfuP{aHwIDCPE;%aqb`Vb89-Ik6v31oKiUv!@goF?uTmy~5))>qvf8_L7q zLatCi)#V0busWPt*`**)p3wjU;k8D&Mwy~u8Z?oz+j?-mNw~9bGvGdEVPvnuqw?}7M$S}coJ@Hq{wL7 z{Jvm?(l`ugiyCT!8# zn}4~+>MdPPT(TI%nZ8Rh$%G@Ruud9r3;+r?V%g-}F@_&hewzgMru{mZ z$L_V1FSNyHQ5$+zYuv;mu#M-T*{>ZCdhZ2{@XbkdMFgMl)Gm?c>{7)qkNPv+v`^Sj zC33IznaYe9y!#RdeC-K9fExbwpv>T~^yKk)txTBB{Tn=?Y#qTMM1m*gcY21rtM@|o zf>op71)80=VS8qZ3TPX68rD9QKTnu`*((Q(!vNyM%Y_*I4=Q`LBEwzIQx74K{fs&u z*c0@gs`&U0-LGCer@g5xLTZ?o>n))q-QC{bPzee;ZD2eWIO4u}M5o;cFrCV$9ssWF zV}JO^KI0BjwY$N$5uS#16h(=@Jgyy=2BWGEC&e%0r*0wWD))gQ(NuQkv94}^!SBX< zmhRIc%-f<6kg9qHkfvji6saV7Se_f&IRFftEOsTFxxKb33~TJRwtKe@bufYbUv5%q zKe!@wIx9GB4a#LQL3cl5XQAG0o9ntWURlR;}ELtJ7$+rygz^%8djo;+xHS?!GD|4Bo)EWf{pZ{?=!Tcze+}i$4|hDrwFK=GEtOurH4eAh zs#rX3XBCTzZYJc~m0k3X`&Q-@<9)^?sGm>fd1qjs(`Du43XOQ@RH6*{pJE5d^Mtp4 zC-@OZgn!U1j}o?R{YE;dlA=5Ahv5?O<-GHMIvcvRKJdEkQ$~y`gy?}Zos}akfta9^$n|#8k4v$sWNwjQm+Sc z7E-ncd>ntqWHa-}zc!+klSyzCnGJ2FasozG2=ws7R4DhpPGO6HP!t94cPZCEf{n(u zTVZ2MLzKfI{=^KaG^4q~ZCAh^SpslDEq{E@4L5zW4C;vvCnAVG4fi=53nkZ11=@DO z^!u0DmxNq&vUo%ei2yXAFs?UVGW@pT1PMxKg~7DJgY&+mlCRp69IZWfB?M%D^#iII zo^N5|i>s%gqjuwm>sS@)%qMDwwvvzY33d?5I^Go;sPd4Lrvb{Ov_`WK6qD6jaoH-( z)O}#iBlI9t9Hdkg5buc!6&ezp+K!!gYWUrC45vfud?8>}0#JjJlWadT0puK+7|nyl zHW+Q(uSt7<%uqMnWsYkyx$rLfbW7bRhkE70GdACcuyc1g3bZ*Qi*PAcm#M%?FLs2$8HuX z1#>fE{d(42{QxmGRnc5ki%D# z>W89`pBD7r8*$^M%5FJSvu)|X0tCF7O7Mz)cRwE{@H(7K4H(F8(u=|FtJK-f|CAc3 zW1)Ba(Ji+hvUMOAyQ!);U(uRH`WzN=3p`)U77Y!#H`=RH()>v2^mCRrGRIAp5!*BM zA1?qj-)*^uuKvf2#ZH9&)#x_oVPCCi!y6 zZ`D?Sm`@(Me~@B%Msw>EIOxQX!4>MS-|B! zgGOIcnPJ74a*a8#)vkoQayL({0?bn_3&^E&DAV^m=&k(C{TO8cbNUSd_Te~9{Nd$~ zczQS%EK z*0(xzpq80FiaOD`OI;ms_pLe6X$>{=Y2vk$W{DHO2!rJbWJNCVk1a?i0!nx zx2?CIJ76*wgr!QF`krHz2aza0o*rp@nfM1bS#h~aNE)pB2vsHK`r+U0>(2(e9K?v` z?G1c0G_U~Jh8~cMm1DYo?j83$ZV$wE#GJ$Q<#)GP2hR4_s*yYKA9bxOeI6xU7W4Jn z0g&jT`<%_3u+MT>h(-~pjz?KyUFdX#dU@U(ZoxmN0K=3B6K{43ufGq(L_r+3>xM~k z&ha<9xo2Fu3#<^#bHV*Ri$ zIh1C_nq@E`EYAwhF)T7H!VVr1@N^&t-!@miVud2VcEEqfJ=6= zNsV|Soxt~;1x_Y~ODSAoFVvejg(PMd% z`7WK>FW^C#JPZ9;D}{qX$=bdeE-2E^am%t_y**4wLR_~=jYs7MJi94UWqO6YVR}hvRC)H*Y!MAOCcP>Y@ zva-thB!D`rPmt?01C(J?Si@g%P*K6zpQZ6v6v5dB=kO3u?e32xubop(#tMpg1MlUG z_07#2_S{yUiH@mF0P!^{2@rgI^YM}qt5U3PWT2>G$T=o5Jb~66<#G-QHIyiYzKOq0 z-2EggF(O_dOl&0^dv>0#WR%kJC`Rv@K6x+OW_gQ)DImwCDyn?pdz?T7i@5^>JrS>* zJO+IjQ1B8s300F^!A$=OVat}kgcy@}V*`OY(^|J_g#Lh#YZRDo0T*bsz{N&E{vO?K zuGz)9d4bob-j|4KS#{l_$>|HJLyxH#@)Fnv?%vYB+W=SO?ZW@Vt86Dke1Qt}k732ayByV=54_@BFwoKdjorHfQT7Aep>XG6UyJkx^>>Z-^St zFK9a8+PuHyF9-ySi#u(S*;XbRkV$Z!&zW~t*49l2>Xri%iS>WKWt)4eaoFnkdZZ(j ze#kdNo_BuH-$*K4>5t9&Pj*RBWD2#pLS9LaMxM!jWVV5EDrjXiPUWCNI_ojn#MxN|=Yp*(DbSMh5SN z)7%1>!30vLfs~oD3smC^(H9hX*m<8O8Cc*`?Yzm)G^dsil^ST9MiQX8@0@LKrP&%e zixQ=3hbCZ}q3T!82~z7oag+YNZ6fyBZQukjkW-1${OR+?>;XWpsWYt`UbG`CI%*SU z$YACfQbyUr`7&7C3tw%V8#mPm;#(dPy^)b5Co5_;dkkT zBQH-P{WB})l0>xVp-*tMmmrc$Lif8`QfD)JL_+||Kh4voD$o6cguYbyY={~W3k3K; z+4WES<$*f$+^g0p(eC~5F^EKxYrFblJ94MrsICmRoT%BV2>wZOIIcf{^9v&Zb#DMTa@BZ z-h)O-`L}~#%{7vz>d@!I<*SVQ)2$9|q2$pfEt2dbE|_Y7-xch#j!b*PnXETxk!Obn z=o|;~ctnRyyCBj_tKWExi-&*J)?J>ykwP9ap$>JC7tPey!>Ao)M9*M(NsafGLxP88 zE!jA_=Jg4d@u_kp4)UE-7YaS_x(6bavlIO8CAZh^*25DTKX~!h6(0N%AbIYEt6jo$ zv&>MR(-toxPcBGjl~HYquUJ7ef5`OyHe~h)m~O^$bl`B}r?IZ#+~?3e9Km{+@V=S7 z6SW@DD$d~frQ7{lj~UZJ<*gHm^SxI4^aHT7*eBn417)k@_lHwcYz+R>7U}|nwR02z zSuVj3+NRZa5X->kN-h}B+8z6c1@e!v$^Va>#Yb5Z@9<2*A>2ypnFzW3tOc08jR=tN z-k$SDrT*p1psUBPpUvzWQGc>_zog_isTy~iSMWxnBZaSIDgU*-tY0ekO)B7cSADFwY4ET{9a-L7`jx9YxpsBnA<$@|6!*y}os0vM`(I@m!oVTVoq`yPkBw+ z+q5Z`wGu;+=W5%{Y>bJHOPuu|$}|nI%URHrE}D~{tRO{>T-MB97yewM7DL`HvRrk* z(Pg6|A`|U1`u41o=c_RSI+BSVwGsj!X!+Ra- ztFsAU1>?I*kPBRG{x}Hh#=Ux|8-89yZ7#*X1GOs<7=FW9a7EhB!D!a?XCjVtfTm=1 zrRH6scABFV`mf{O%IofD?d=*Q;Px>c=g{)$(r&;$1STRO>1yq{T`_KUWciQ6|0f&p z&R;CJIbA2}?KZVmBkA|_X@o?u8#o)=%-wkrd613gsxfQ~gbHw6-&(s$^aC*G_Av(0^7BEy9S z010R;IlHccP4Gu+T?=2TZ6r%9C*f<2$GDz~w#?KZRv2=z>D!uY&}nfAl^_s0(D;C= zev7x@TPk*9&zIiiguELsk{Hk_<_olkiwO5vJzq%KRHvA18oPMfg@~0uOpTPB(3^i% zG#wJK$CEuy$aUJ0{ffV2sw1H|A2hqCN)_4mx0}iTs0)3R`S7B4Yw1wuJ1QBoZH?27 z--bc~#|6sD_HsNF0X0(;Ow}ewhPLOw-mON4_ustY+Yp!SSZ6vI&UOGO?3{(^&|*R9t1rKKl>|aBG-310FCNS zVEpUp2vr||zC&Ngt2OzZ+8F>rZII|XABiEwH zFHP!92670ctBaX)mEDltO58Gu#Q`mH71nn&4h{AeQo#bhM*idv0HX(Fd-?DDmlsA6 zfAR;2+G80#FuZ<4pGm21S0k24sf3EZ9|hcb|Ic#%52N$yv`aR@uTc*7`zi~}fTKOB z`HOEj(mD@sXDn(eS#w_!#Ai@h{hQk3hUKA zBjkCFjDgs)TglZMk&64RU;X7PTKS3oNg?1wY~@EWB}&J(8d-dQ+Ft1O&7lPB(v?+Z zZc0}CBgKmO<=!xTGw1p98NmenTBrpbO?Qk;z_cd|pIj+@;jJ7)oZiVID>rV`8FX_mP=|4raucs>Zl3 zH@*pAHkS9I6oEzlSg_8~)J&-DM*4q*B>&?^Y0UET>0*Lp18RngUm?l-(s=R!{5rBq zst>hhj3pBIuQAESJJ2qgt9>Pr#_OlQomkIQ2Ux4wiw6Oh5a?t535NaEghRj1`JX%j zOQk!aJXjaPaDiU-Te@>UIQ=4E*PtUYZ$s21LeLtp#n@q@pVPd(*BRZ=%p-5a8p2ksn z{-If+N@p;x%SQ=Dfeba}>@y>Ejk>nd+NE{C!UHb#)qSW@K_R#NcO*gQpGX3bflMOy zdoY<8E9skNT3cCZ*vUslC3Kn=Z1fRRn~C?y2YqcoO2h$w2N1sA;N**=+F~bumSM9W z&;2u2`Jcz{d|Br;$;V5&7w5I1kE1?9uggD(o@+#RVs9p@cJlrk`pi6E>or6SE}L2D z&AW!_Ie9Idk?HAq&nm|9HZd1pi~B3Rt@^C$PZ8c&e(wi8WSBL;F4>b{sXtqm_>hHS z+qe%GA|v^9l;ES}^=Mkf5$DFo;?VEDDgq`J+=-a^*VMxyQc9n7VyU;+G^h`NKgt}^ zY$n|i4x+BEUSb-~MPRz#^?=}`N_z1utH0=rohgaTh^y>5G7F?}9122ga?8j<|0jkf z!OqKa?D1${e|?A!9}B<7-7G9RO43c@`EqNU-sv7Qh?PY`@ez={TN2Pu&$O5wQxedt zCulO7o+>PR`t-J;>%3tlaIL#p2V8dTgrFXCOmNlmvQ-uTuNBbA2%x5y+$+BF!a3go z1W~#i)X5{H59I3!egBR00xSg_$^CQ$q%L$C8~Singrq${b#xe3EK$D750JR*5lGFe z0P+JCI}(Du&nJRIs|@V98^vH1=|SV(hgq1SW&$4bta5p^{R^Nd-i%ABSM*0@6XWvvEwsG@M zguwiR+y!Ueb~gIOhx6+V%j~rq>IR9pmv>Y#oU>_I4udB?VjNd4I7rrTFq`)iQ!`dY z{x~klQVMY&s4A0o*X}=M>HjqCYQ#2PgA1qf!svN(mLio2fFnZcL3s7)k*dS+Tz|}) ztba9JceVKFOF&C^T8{}(b@m1xG!K9Az;l3vjJcJa{6d0stFyfjh=H}$8OFXK{rFi# zP!?I*&m=iEvBoq&Go0^mpIxlP+EHchBYK$hTHy_7anoWmli0~q$wE4Sj1jCie=iSwYf>s|J0!p{*lDTV@N_@#iEssbDPCA{w9>=Qwt&!x zR+eB9q1>00MXs^ALh2zhq=W&*fl(yTr+1erf4yqStcFq+RRBV4HCx)I7^3=>kS;vG zm5_7I-<}ZXuwP4ia#QUe|%YrBO;m1{mPVDorxD)60x%6X*&5f2`s1 zr;Vf-4))}*#}!LHz&+J*RnMtUD{l~d&6xfCubwVIT{vk8!r~w%op9}vQYLYdH;?bT zD}`qcG(O{m9tQ@)uG8`WS6v6KvAPuD`GM<#Z%3v%iR{tpu=qa316{ z>o7%_(PK%^^s2V7BDF{>6f&)fBd++TIg#xq~}V>ZZMSO21isB z2byuyFRKu*WtfINCUu@61shQ+o4)V|f%W3jDNA)I|2Qnd z`@9tJW4;bPE%EhDQicHbfsZKCNeD46Kr$KG8pUJWCEu?H1phT{K5CFN;ur?kS(A|Ney2p^ru=O3yI(Y z-%E-TmS>q7wJzug#G>m#ZaDU9#x(60UnbE-4RS$gR_9S-MxfnB z%wm;S6#NNKK3RAHVAL+*fH1_W>dEoyjf~m4e|316U->VR@MmLjvED1dGOoRjAU^+QY#=BQB26#v}A_?A@a+=M>X^Nk#UFbPJL&7v5gsi6%7?lP17GMg(?C zw72OVkKkwRvzs)_)WhQJ1frq2HyJ#d*fc#TLGaTK!~F>|S>rWEir_@ZvIRGmh4HjW z=6zAV4pd`^YGXsS^DPDWUH{OBHO#U%Bzb7Li}N56sZ~!k=mhuLV`w76!)Rm)OY)-( z!7K`}wI&nwkXM5N4kh=2!vmmn?Fc8;e7+Vz`o>5SQeE|hLLlpp9H$t#2^or)_1Q}X z)EeV}1*~@qcCXh}^!EAL{;EkoIL*bVQyIL4q88L{op0%&6>A818l?tC(qJ1~v?hi+ zlSRLiGi`7db{5r@`g5EE|2nnW@jltY6UozoKzZbXZb*}yAhKAtUqj8&Ryj!MFdZf=EtDeHH|8JQT6-syv>ct)#$IuvLrJ<9S8S+zUwyVVU`>X4=*;2 zlW|>;Qj&JI&Gli6T=bszS32&ZAFPkaqv?+$Qem7Nj3mD!dm~Z!r;nM+_y4GI!fHJi zqTNvV&;GZrVu0`;EbJ`3jfZ%>ExrwC{tk01|1WF}Hx9iF94B8H9=#wOZJvsypw*rw z20RT_O>eQDpH|E@Ot`QlKV7}J*x)rPlH?6Ix){ENhhOPWLPm99atAEKwK$^o)9>D> z4A&=8QO~~`RSQk@vh(UGk@P+L>|r7?i|U+iXLq$Z{h=?TQ148E`b*YjB=o7A|9lp7 zjY5jinD5PZ!%a9lNXtZ)GM|oBMJ3=xmiFWlsh|CwPcC?CcMGDJ=xy`O()>&g zZV9FrkkR!rwJxOTEyXZ0oaimJh6js)WpugnLLUuvCzI(ry(hufo`_{_HZQ~?JwFF3 zQa5xUfeQ6*B$`g!?;2gAQyN-(ECx$$PDeZ3y4;QA&I6_SHFFB+$(8G z<9slo>X2q2Il)!&>R%PiJKw#0&62+l)#vzR*iKt7*eU#JM9eO$Eb(8AJa77c zsQd4zCiAop7)L=sDFIOdfkb3RbU+YMYKn-6jtaJcAV|w-Mx{q;LKEpFI*b$viOM*r zL`lr3AYC8u9e7PRrI57Ha0s;zTorQQN9TZ$-7kw|vn7q6eev}9%+IN5fL8Nkab|g5j-dnFOVCK4f4zWyJf(1y_zGtF`RBOWJ8y`$!cSS)QN-I{qVqYtX;|ZM_vxSj=e=3) zF6}s@Yt#Fi%)2t}@3XEQE~gw*v{1i|2u{;{D4No5{8Ox!wvwt3*25g*PvjYRk0gVl zZXb?1wz9omx-Ut+D#BYXS$xgABliVSz55HN(7`dn0rQZj$wyRn@#-BN5x0(6-0bPe^~%UaP`y9O6cJ@swqtzjT{R=d z)J&@1<4gTMJY~rErOs}Om1x!JD_C?b=!2rBx}<6bRii+#`1t~SK|>+w7^d-u8VRx` zxjaOpboHv|1sQ+mv|-UklftgI))?G5^z?|I|tD{ad3>WVK zb$vKza7!0Y#Q!=V(LTt7Zkl58T%Kg=LYlneLi1iZ1rmm&E^iMoiCNo zktDQY9b$WhHMdeF~O66ZWk_;=qFeM1Gah-ScJQW zvFmO$XVT$nMVn(*B6i6u4!O79H1_bDCT5CvH$iLM6}F`O1l)V{r?!*PC)8adp6S_Y zeM&eZ%mdK#gy;A9otI$S93Xz=aZ|66>)(-PQ>jQJGez+~=WDsdi>|*I`#}vcc}$+4 z(k0qD^b*_y^M>%65Z|^Y&@*ckk%B`?AI~!Takta^^=_yd0L;Q?Tv>>o*@lSg}jwUaTFNsXUQMI-+!GvcSa@v|RQn{+<548Ccb z!|RM{0z@C;SytzpB%rUZ)aa6q`jUVc;lZ2c`j)~n0o(=mGs?vMG^S`XcDeJ;Embd^ z7WJv-QRKsCQxCrwRWyN9lsffu0nH_7;=NEr+8PvR$d7T|Id%E`*jnP@LNH zbc3kQ-LM;*VXA4lFM3a$#U33|blA?F_|wG~_uX5cEobdSBMC3G3?KuF)UJObS?87T7w9%ri4O7jJ>0!-+;e>gik+nHi+c-*Q{4AjiCKbbZ7$Z8f|@7h^m zGLrNI_pELdXZRp@ComM7lx_xFm_R8%K8Y8dqWpGoO~EBP=oDb^{mV*uLQZ}Gw6vQg z{eFE!5n%b_$CKQ@R2LGvG`b9NOauAjc;|mLmo>`lY-#rS+AA88-+zrAf*FE=#7BD< zPAco^E(Irz>K5*F$g9!R#0u2AelvwkQjCrxMIEOfRjs$C*5|4taA`MYmKlE#-kSn5 z#Ze~8T}ykO(DOLD4g2IhM%0oO6Ri9I?|>2BZy^^9@dFH?$4&g+m%j4zc^~%tUc#m8 zTaL`6D%Lul{7J_0d%I%a`Fi>#{!VJJ59(Oj4bC>B*i6w~dtfc?L*#vHHQZRTsn}QV zr4fR^zx3?5Bn_2$HvQ(XqO4A2El>&a4wdYBCaVKi#58Vm^lLa*Gs+)7T6=y!z-r%m zDUr{S-3ZLLSFg?8a}PxBng8H_@mk(rmv8geP!ASz1KuM#Zp-h8*%i!gL!Em3-MY8A zTFaWf=Kl|veQmtF3g4?Y7Rk>ROM^3kKMG?Kv4?%PIW8&MY*zUJShEpBg=|2W2zi>p zP4Q}mr^m01ZA`YBulvbqCGiKPn0Iyf@+i5Kx)*QTX*qF;zkHVimOB>gt!Sw;dde($ zzP%%RmyT7>?F7%|_{>w0z;=se=_{TMXp#B&yR_eDK4(3T$a}Z{SNSu2yW%gPlO~dP z#P2(Sx z{fq;OXwx2Xuk6a4wu1m=f=y>9>e z7ys9H{{5q~db||VH%(GNbh0WSOONyAk%M~GUVyE&$6T|vaZv*0&JnlUMh%f~Nk#8w zYtvS&*jzUVambOJI)Izv3yvn^1=eglWi+{`1S3C~fR?nI;cJOVCUZy7YfT>SaxeSF z9I9e-n91!3UKcwfFBw+NIgmqJ?bTezZpm8K;C=VUwd~J%=+Rzm*kkR7!{(N4+WFB} zZLPOWV-v=BalNMEvHq^y!9McnCBEIzK7@ZJAC!QDaU6#W9dwMokTl{Z7L zwRmaE8l%|;ccx2YVy}6M#}iUJYx2?8vcFINw}b!pL;T0%0DdYP@83QqhscHhG-%IW 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 z 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ª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

TfI71 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 F{|jFJ9FPD2 From fc020afc597986b9cc37cc48133d85749b6d85de Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Sun, 21 Dec 2025 00:24:54 +0100 Subject: [PATCH 12/14] refactor(executor): modernize executor with internal io_context and graceful shutdown - Refactor executor to own its io_context and run it in a dedicated thread - Replace three atomic bools with single state enum (stopped/starting/running/stopping) - Move user_agent configuration from executor to full_node - Add stopped() checks to all peer_manager async methods to prevent strand access after pool shutdown (fixes segfault on Ctrl-C) - Fix signal handling in wait_for_stop_signal() with proper work_guard - Update C API to use new executor interface - Improve TUI dashboard with network statistics display - Inline KTH_* message macros directly where used --- .../kth/blockchain/pools/header_organizer.hpp | 5 + src/blockchain/src/pools/header_organizer.cpp | 7 + src/c-api/src/node.cpp | 49 +- .../include/kth/network/peer_session.hpp | 38 ++ src/network/src/handlers/pong.cpp | 10 +- src/network/src/p2p_node.cpp | 23 + src/network/src/peer_manager.cpp | 25 +- src/network/src/peer_session.cpp | 52 ++ src/network/src/settings.cpp | 5 +- src/node-exe/src/main.cpp | 69 ++- src/node-exe/src/tui_dashboard.cpp | 244 +++++++- src/node-exe/src/tui_dashboard.hpp | 22 + .../include/kth/node/executor/executor.hpp | 168 +++--- src/node/include/kth/node/full_node.hpp | 1 + src/node/include/kth/node/sync_session.hpp | 8 +- src/node/src/executor/executor.cpp | 521 ++++++++++-------- src/node/src/full_node.cpp | 22 +- src/node/src/sync_session.cpp | 48 +- 18 files changed, 897 insertions(+), 420 deletions(-) diff --git a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp index adfbb8b7..9cdce50a 100644 --- a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp @@ -106,6 +106,11 @@ struct KB_API header_organizer { [[nodiscard]] hash_digest const& header_tip_hash() const { return tip_hash_; } + /// Get the timestamp of the header tip. + /// Used for BCHN-style progress calculation. + [[nodiscard]] + uint32_t tip_timestamp() const; + /// Get the number of headers in the index. [[nodiscard]] size_t size() const { return index_.size(); } diff --git a/src/blockchain/src/pools/header_organizer.cpp b/src/blockchain/src/pools/header_organizer.cpp index a9f05ee6..2477980b 100644 --- a/src/blockchain/src/pools/header_organizer.cpp +++ b/src/blockchain/src/pools/header_organizer.cpp @@ -149,6 +149,13 @@ int32_t header_organizer::header_height() const { return index_.get_height(tip_index_); } +uint32_t header_organizer::tip_timestamp() const { + if (tip_index_ == header_index::null_index) { + return 0; + } + return index_.get_timestamp(tip_index_); +} + // ============================================================================= // Validation // ============================================================================= diff --git a/src/c-api/src/node.cpp b/src/c-api/src/node.cpp index 0d5dca0c..19bbf6be 100644 --- a/src/c-api/src/node.cpp +++ b/src/c-api/src/node.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -55,48 +54,42 @@ int kth_node_initchain(kth_node_t node) { #if ! defined(KTH_DB_READONLY) void kth_node_init_run_and_wait_for_signal(kth_node_t node, void* ctx, kth_start_modules_t mods, kth_run_handler_t handler) { - kth_node_cpp(node).init_run_and_wait_for_signal( - version(), - kth::start_modules_to_cpp(mods), - [node, ctx, handler](std::error_code const& ec) { - if (handler != nullptr) { - handler(node, ctx, kth::to_c_err(ec)); - } - }); + // Start node + auto ec = kth_node_cpp(node).start(); + if (handler != nullptr) { + handler(node, ctx, kth::to_c_err(ec)); + } + + if (ec == kth::error::success) { + // Wait for signal + kth_node_cpp(node).wait_for_stop_signal(); + // Stop node + kth_node_cpp(node).stop(); + } } void kth_node_init_run(kth_node_t node, void* ctx, kth_start_modules_t mods, kth_run_handler_t handler) { - kth_node_cpp(node).init_run(version(), kth::start_modules_to_cpp(mods), - [node, ctx, handler](std::error_code const& ec) { - if (handler != nullptr) { - handler(node, ctx, kth::to_c_err(ec)); - } + kth_node_cpp(node).start_async([node, ctx, handler](kth::code ec) { + if (handler != nullptr) { + handler(node, ctx, kth::to_c_err(ec)); + } }); } kth_error_code_t kth_node_init_run_sync(kth_node_t node, kth_start_modules_t mods) { - std::latch latch(1); //Note: workaround to fix an error on some versions of Boost.Threads - kth_error_code_t res; - - kth_node_cpp(node).init_run(version(), kth::start_modules_to_cpp(mods), - [&](std::error_code const& ec) { - res = kth::to_c_err(ec); - latch.count_down(); - } - ); - - latch.wait(); - return res; + auto ec = kth_node_cpp(node).start(); + return kth::to_c_err(ec); } #endif // ! defined(KTH_DB_READONLY) void kth_node_signal_stop(kth_node_t node) { - kth_node_cpp(node).signal_stop(); + kth_node_cpp(node).stop_async(); } int kth_node_close(kth_node_t node) { - return kth_node_cpp(node).close(); + kth_node_cpp(node).stop(); + return 1; // Success } int kth_node_stopped(kth_node_t node) { diff --git a/src/network/include/kth/network/peer_session.hpp b/src/network/include/kth/network/peer_session.hpp index c791d337..56c03a32 100644 --- a/src/network/include/kth/network/peer_session.hpp +++ b/src/network/include/kth/network/peer_session.hpp @@ -232,6 +232,32 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] bool is_preferred_download() const; + // ------------------------------------------------------------------------- + // Statistics (lock-free, benign data races acceptable) + // ------------------------------------------------------------------------- + + /// Get total bytes received from this peer + [[nodiscard]] + size_t bytes_received() const; + + /// Get total bytes sent to this peer + [[nodiscard]] + size_t bytes_sent() const; + + /// Get last ping latency in milliseconds + [[nodiscard]] + uint32_t ping_latency_ms() const; + + /// Record a ping sent (store nonce and time for latency calculation) + void record_ping_sent(uint64_t nonce); + + /// Record a pong received, returns true if nonce matches pending ping + bool record_pong_received(uint64_t nonce); + + /// Get connection time + [[nodiscard]] + std::chrono::steady_clock::time_point connection_time() const; + private: // ------------------------------------------------------------------------- // Internal coroutines @@ -303,6 +329,18 @@ class KN_API peer_session : public std::enable_shared_from_this { std::atomic one_shot_{false}; std::atomic permission_flags_{uint32_t(permission_flags::none)}; + // Statistics (lock-free, benign data races acceptable) + std::atomic bytes_received_{0}; + std::atomic bytes_sent_{0}; + std::atomic ping_latency_ms_{0}; + std::chrono::steady_clock::time_point connection_time_{std::chrono::steady_clock::now()}; + + // Ping tracking (lock-free) + // We store time as nanoseconds since steady_clock epoch for atomic access + // Benign data races are acceptable for statistics + std::atomic pending_ping_nonce_{0}; + std::atomic pending_ping_time_ns_{0}; + // Buffers (only accessed from read_loop, no synchronization needed) data_chunk heading_buffer_; }; diff --git a/src/network/src/handlers/pong.cpp b/src/network/src/handlers/pong.cpp index 577cc33b..68f377da 100644 --- a/src/network/src/handlers/pong.cpp +++ b/src/network/src/handlers/pong.cpp @@ -13,8 +13,14 @@ ::asio::awaitable handle( peer_session& peer, domain::message::pong const& msg) { - // Just acknowledge receipt - could verify nonce if we tracked sent pings - spdlog::trace("[pong] Received pong from [{}], nonce: {}", peer.authority(), msg.nonce()); + // Record pong to calculate latency + if (peer.record_pong_received(msg.nonce())) { + spdlog::trace("[pong] Received pong from [{}], nonce: {}, latency: {}ms", + peer.authority(), msg.nonce(), peer.ping_latency_ms()); + } else { + spdlog::trace("[pong] Received unexpected pong from [{}], nonce: {}", + peer.authority(), msg.nonce()); + } co_return message_result::handled; } diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp index 1bda321b..0645c472 100644 --- a/src/network/src/p2p_node.cpp +++ b/src/network/src/p2p_node.cpp @@ -272,6 +272,17 @@ awaitable_expected p2p_node::connect( host, port, handshake_result->negotiated_version, handshake_result->peer_version->user_agent()); + // Send initial ping immediately to get latency data quickly (like BCHN) + { + uint64_t nonce = 0; + pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); + domain::message::ping ping_msg(nonce); + auto ec = co_await peer->send(ping_msg); + if (ec == error::success) { + peer->record_ping_sent(nonce); + } + } + // Add to peer manager auto ec = co_await manager_.add(peer); if (ec != error::success) { @@ -567,6 +578,17 @@ ::asio::awaitable p2p_node::run_inbound() { peer->authority(), handshake_result->negotiated_version, handshake_result->peer_version->user_agent()); + // Send initial ping immediately to get latency data quickly (like BCHN) + { + uint64_t nonce = 0; + pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); + domain::message::ping ping_msg(nonce); + auto ec = co_await peer->send(ping_msg); + if (ec == error::success) { + peer->record_ping_sent(nonce); + } + } + // Add to peer manager auto ec = co_await manager_.add(peer); if (ec != error::success) { @@ -615,6 +637,7 @@ ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { spdlog::debug("[p2p_node] Failed to send ping to [{}]", peer->authority()); break; } + peer->record_ping_sent(nonce); spdlog::trace("[p2p_node] Sent ping to [{}]", peer->authority()); } continue; diff --git a/src/network/src/peer_manager.cpp b/src/network/src/peer_manager.cpp index 6d40245e..44b23dab 100644 --- a/src/network/src/peer_manager.cpp +++ b/src/network/src/peer_manager.cpp @@ -88,7 +88,7 @@ ::asio::awaitable peer_manager::add(peer_session::ptr peer) { } ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { - if (!peer) { + if (!peer || stopped()) { co_return; } @@ -102,6 +102,11 @@ ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { } ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { + // Skip if already stopped - the destructor will handle cleanup + if (stopped()) { + co_return; + } + co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { auto it = peers_.find(nonce); if (it != peers_.end()) { @@ -115,6 +120,9 @@ ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { } ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { + if (stopped()) { + co_return false; + } co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { co_return peers_.find(nonce) != peers_.end(); }, ::asio::use_awaitable); @@ -123,6 +131,9 @@ ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { ::asio::awaitable peer_manager::exists_by_authority( infrastructure::config::authority const& authority) const { + if (stopped()) { + co_return false; + } co_return co_await ::asio::co_spawn(strand_, [this, &authority]() -> ::asio::awaitable { for (auto const& [nonce, peer] : peers_) { if (peer->authority() == authority) { @@ -134,6 +145,9 @@ ::asio::awaitable peer_manager::exists_by_authority( } ::asio::awaitable peer_manager::exists_by_ip(::asio::ip::address const& ip) const { + if (stopped()) { + co_return false; + } co_return co_await ::asio::co_spawn(strand_, [this, &ip]() -> ::asio::awaitable { for (auto const& [nonce, peer] : peers_) { if (peer->authority().asio_ip() == ip) { @@ -145,6 +159,9 @@ ::asio::awaitable peer_manager::exists_by_ip(::asio::ip::address const& ip } ::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) const { + if (stopped()) { + co_return nullptr; + } co_return co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { auto it = peers_.find(nonce); if (it != peers_.end()) { @@ -155,6 +172,9 @@ ::asio::awaitable peer_manager::find_by_nonce(uint64_t nonce) } ::asio::awaitable> peer_manager::all() const { + if (stopped()) { + co_return std::vector{}; + } co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable> { std::vector result; result.reserve(peers_.size()); @@ -166,6 +186,9 @@ ::asio::awaitable> peer_manager::all() const { } ::asio::awaitable peer_manager::count() const { + if (stopped()) { + co_return 0; + } co_return co_await ::asio::co_spawn(strand_, [this]() -> ::asio::awaitable { co_return peers_.size(); }, ::asio::use_awaitable); diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp index f5095591..f78cfb24 100644 --- a/src/network/src/peer_session.cpp +++ b/src/network/src/peer_session.cpp @@ -31,6 +31,7 @@ boost::unordered_flat_map const known_client {"Knuth:", "KTH"}, {"Bitcoin ABC:", "ABC"}, {"BitcoinUnlimited:", "BU"}, + {"BCH Unlimited:", "BU"}, {"BUCash:", "BU"}, }; @@ -318,6 +319,51 @@ bool peer_session::is_preferred_download() const { && !is_client(); } +// ============================================================================= +// Statistics (lock-free, benign data races acceptable) +// ============================================================================= + +size_t peer_session::bytes_received() const { + return bytes_received_.load(std::memory_order_relaxed); +} + +size_t peer_session::bytes_sent() const { + return bytes_sent_.load(std::memory_order_relaxed); +} + +uint32_t peer_session::ping_latency_ms() const { + return ping_latency_ms_.load(std::memory_order_relaxed); +} + +void peer_session::record_ping_sent(uint64_t nonce) { + // Store time as nanoseconds since steady_clock epoch for lock-free access + auto const now = std::chrono::steady_clock::now(); + auto const ns = std::chrono::duration_cast( + now.time_since_epoch()).count(); + pending_ping_time_ns_.store(ns, std::memory_order_relaxed); + pending_ping_nonce_.store(nonce, std::memory_order_relaxed); +} + +bool peer_session::record_pong_received(uint64_t nonce) { + auto const expected_nonce = pending_ping_nonce_.load(std::memory_order_relaxed); + if (expected_nonce == 0 || nonce != expected_nonce) { + return false; + } + + auto const sent_ns = pending_ping_time_ns_.load(std::memory_order_relaxed); + auto const now = std::chrono::steady_clock::now(); + auto const now_ns = std::chrono::duration_cast( + now.time_since_epoch()).count(); + auto const latency_ms = static_cast((now_ns - sent_ns) / 1'000'000); + ping_latency_ms_.store(latency_ms, std::memory_order_relaxed); + pending_ping_nonce_.store(0, std::memory_order_relaxed); + return true; +} + +std::chrono::steady_clock::time_point peer_session::connection_time() const { + return connection_time_; +} + // ============================================================================= // Internal Coroutines // ============================================================================= @@ -374,6 +420,9 @@ ::asio::awaitable peer_session::write_loop() { co_return; } + // Track bytes sent + bytes_sent_.fetch_add(bytes_written, std::memory_order_relaxed); + spdlog::trace("[peer_session] Sent {} bytes to [{}]", bytes_written, authority()); } } @@ -479,6 +528,9 @@ awaitable_expected peer_session::read_message() { co_return std::unexpected(error::bad_stream); } + // Track bytes received (header + payload) + bytes_received_.fetch_add(heading::maximum_size() + head.payload_size(), std::memory_order_relaxed); + spdlog::debug("[peer_session] Received {} from [{}] ({} bytes)", head.command(), authority_with_agent(), head.payload_size()); diff --git a/src/network/src/settings.cpp b/src/network/src/settings.cpp index ac1ca138..6158b2f7 100644 --- a/src/network/src/settings.cpp +++ b/src/network/src/settings.cpp @@ -31,7 +31,7 @@ settings::settings() , connect_batch_size(5) , connect_timeout_seconds(5) , channel_handshake_seconds(6000) - , channel_heartbeat_minutes(5) + , channel_heartbeat_minutes(2) // BCHN: PING_INTERVAL = 2 minutes , channel_inactivity_minutes(10) , channel_expiration_minutes(60) , channel_germination_seconds(30) @@ -85,6 +85,9 @@ settings::settings(domain::config::network context) seeds.emplace_back("dnsseed.electroncash.de", 8333); // Electroncash.de seeds.emplace_back("bchseed.c3-soft.com", 8333); // C3 Soft (NilacTheGrim) seeds.emplace_back("bch.bitjson.com", 8333); // Jason Dreyzehner + + // TODO(fernando): TEMPORARY - hardcoded peer for testing + peers.emplace_back("194.14.247.36", 8333); #else identifier = netmagic::btc_mainnet; seeds.reserve(6); diff --git a/src/node-exe/src/main.cpp b/src/node-exe/src/main.cpp index f5f89ce9..274316d5 100644 --- a/src/node-exe/src/main.cpp +++ b/src/node-exe/src/main.cpp @@ -2,17 +2,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include - #include -#include -#include #include +#include #include #include #include -#include #include #include #include @@ -29,25 +27,33 @@ std::string version() { void do_help(kth::node::parser& metadata, std::ostream& output) { auto const options = metadata.load_options(); - kth::infrastructure::config::printer help(options, application_name, KTH_INFORMATION_MESSAGE); + kth::infrastructure::config::printer help(options, application_name, "Runs a Bitcoin Cash full-node."); help.initialize(); help.commandline(output); } void do_settings(kth::node::parser& metadata, std::ostream& output) { auto const settings = metadata.load_settings(); - kth::infrastructure::config::printer print(settings, application_name, KTH_SETTINGS_MESSAGE); + kth::infrastructure::config::printer print(settings, application_name, "These are the configuration settings that can be set."); print.initialize(); print.settings(output); } bool run_with_log(kth::node::executor& host) { // Traditional log mode - scrolling output - return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { - if (ec != kth::error::success) { - host.signal_stop(); - } - }); + + // Start node (blocks until ready) + auto ec = host.start(); + if (ec != kth::error::success) { + return false; + } + + // Wait for SIGINT/SIGTERM + host.wait_for_stop_signal(); + + // Stop node (blocks until stopped) + host.stop(); + return true; } bool run_with_tui(kth::node::executor& host) { @@ -65,7 +71,7 @@ bool run_with_tui(kth::node::executor& host) { status.version = std::string(kth::version); status.network_name = "BCH Mainnet"; // TODO: get from config status.state = kth::node_exe::node_status::sync_state::starting; - status.start_time = std::chrono::system_clock::now(); // Initialize start time + status.start_time = std::chrono::system_clock::now(); dashboard->update_status(status); // Start TUI @@ -76,44 +82,33 @@ bool run_with_tui(kth::node::executor& host) { return run_with_log(host); // Fallback to log mode } - // Run node (non-blocking) - bool init_ok = host.init_run(version(), kth::node::start_modules::all, [&host, &dashboard, &status](std::error_code const& ec) { - if (ec != kth::error::success) { - status.state = kth::node_exe::node_status::sync_state::error; - dashboard->update_status(status); - dashboard->request_exit(); // Signal TUI to exit on error - } - }); - - if (!init_ok) { + // Start node (blocks until ready) + auto ec = host.start(); + if (ec != kth::error::success) { dashboard->stop(); return false; } - // TODO(fernando): Update dashboard periodically with node status - // This would be done via a callback mechanism from the node + // Update status to syncing headers + status.state = kth::node_exe::node_status::sync_state::syncing_headers; + dashboard->update_status(status); - // Wait for TUI exit (user pressed q or ESC, or node error) + // Wait for TUI exit (user pressed q or ESC) while (dashboard->is_running()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - // Stop node if TUI exited - if (!host.stopped()) { - host.signal_stop(); - } - + // Stop TUI first dashboard->stop(); - return host.close(); + + // Stop node (blocks until stopped) + host.stop(); + return true; } bool run_daemon(kth::node::executor& host) { - // Daemon mode - minimal output, suitable for systemd - return host.init_run_and_wait_for_signal(version(), kth::node::start_modules::all, [&host](std::error_code const& ec) { - if (ec != kth::error::success) { - host.signal_stop(); - } - }); + // Daemon mode - same as log mode but for systemd + return run_with_log(host); } bool run(kth::node::executor& host, kth::display_mode mode) { diff --git a/src/node-exe/src/tui_dashboard.cpp b/src/node-exe/src/tui_dashboard.cpp index 72ceab59..e0c9bec0 100644 --- a/src/node-exe/src/tui_dashboard.cpp +++ b/src/node-exe/src/tui_dashboard.cpp @@ -62,13 +62,14 @@ tui_dashboard::tui_dashboard() { splash_start_ = std::chrono::steady_clock::now(); // Define navigable screens (after splash) + // TODO: Only DASHBOARD and LOGS for now, others coming later navigable_screens_ = { screen_id::dashboard, - screen_id::network, - screen_id::blockchain, - screen_id::mempool, + // screen_id::network, + // screen_id::blockchain, + // screen_id::mempool, screen_id::logs, - screen_id::terminal, + // screen_id::terminal, }; // Initialize terminal with welcome message @@ -242,6 +243,21 @@ void tui_dashboard::update_status(node_status const& status) { } } +void tui_dashboard::add_log(std::string const& message) { + { + std::lock_guard lock(status_mutex_); + status_.recent_logs.push_back(message); + // Keep only last 100 logs + while (status_.recent_logs.size() > 100) { + status_.recent_logs.erase(status_.recent_logs.begin()); + } + } + auto* scr = screen_.load(); + if (scr != nullptr) { + scr->PostEvent(Event::Custom); + } +} + bool tui_dashboard::is_running() const { return running_; } @@ -514,7 +530,107 @@ Element tui_dashboard::render_dashboard() { } Element tui_dashboard::render_network_screen() { - return render_placeholder("NETWORK"); + Elements peer_rows; + + // Header row + peer_rows.push_back(hbox({ + text(" ") | size(WIDTH, EQUAL, 2), + text("ADDRESS") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 22), + text("USER AGENT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 16), + text("HEIGHT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), + text("RECV") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), + text("SENT") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 10), + text("PING") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 8), + text("TIME") | bold | color(colors::kth_light) | size(WIDTH, EQUAL, 8), + })); + + peer_rows.push_back(separator() | color(colors::dark_gray)); + + if (status_.peers.empty()) { + peer_rows.push_back(text(" No peers connected...") | color(colors::gray) | dim); + } else { + for (auto const& peer : status_.peers) { + // Direction indicator + auto direction = peer.is_inbound ? + text("↓ ") | color(colors::kth_violet) : + text("↑ ") | color(colors::cyan); + + // Ping color based on latency + auto ping_col = peer.ping_ms == 0 ? colors::gray : + peer.ping_ms < 100 ? colors::green : + peer.ping_ms < 300 ? colors::orange : colors::red; + + auto ping_str = peer.ping_ms > 0 ? + std::to_string(peer.ping_ms) + "ms" : "-"; + + // Connected time + auto time_str = format_duration(peer.connected_duration); + // Shorten to just the most significant part + if (peer.connected_duration.count() >= 86400) { + time_str = std::to_string(peer.connected_duration.count() / 86400) + "d"; + } else if (peer.connected_duration.count() >= 3600) { + time_str = std::to_string(peer.connected_duration.count() / 3600) + "h"; + } else if (peer.connected_duration.count() >= 60) { + time_str = std::to_string(peer.connected_duration.count() / 60) + "m"; + } else { + time_str = std::to_string(peer.connected_duration.count()) + "s"; + } + + // User agent - truncate if too long + auto user_agent = peer.user_agent; + if (user_agent.length() > 14) { + user_agent = user_agent.substr(0, 14) + ".."; + } + if (user_agent.empty()) { + user_agent = "Unknown"; + } + + // Preferred indicator + auto preferred_indicator = peer.is_preferred ? + text("★") | color(colors::bch_green) | bold : + text(" "); + + peer_rows.push_back(hbox({ + direction, + text(peer.address) | color(colors::white) | size(WIDTH, EQUAL, 22), + text(user_agent) | color(colors::cyan) | size(WIDTH, EQUAL, 16), + text(format_number(peer.start_height)) | color(colors::gray) | size(WIDTH, EQUAL, 10), + text(format_bytes(peer.bytes_received)) | color(colors::green) | size(WIDTH, EQUAL, 10), + text(format_bytes(peer.bytes_sent)) | color(colors::blue) | size(WIDTH, EQUAL, 10), + text(ping_str) | color(ping_col) | size(WIDTH, EQUAL, 8), + text(time_str) | color(colors::gray) | size(WIDTH, EQUAL, 8), + })); + } + } + + // Summary footer + Elements summary; + summary.push_back(separator() | color(colors::dark_gray)); + summary.push_back(hbox({ + text("Total: ") | color(colors::gray), + text(std::to_string(status_.peers_outbound + status_.peers_inbound)) | bold | color(colors::white), + text(" peers (") | color(colors::gray), + text("↑" + std::to_string(status_.peers_outbound)) | color(colors::cyan), + text(" out, ") | color(colors::gray), + text("↓" + std::to_string(status_.peers_inbound)) | color(colors::kth_violet), + text(" in)") | color(colors::gray), + filler(), + text("Avg ping: ") | color(colors::gray), + text(status_.avg_ping_ms > 0 ? std::to_string(status_.avg_ping_ms) + "ms" : "-") | + color(status_.avg_ping_ms < 100 ? colors::green : + status_.avg_ping_ms < 300 ? colors::orange : colors::red), + })); + + return vbox({ + render_header_bar(), + separator() | color(colors::dark_gray), + window(text(" ⚡ CONNECTED PEERS ") | bold | color(colors::cyan), + vbox(peer_rows) | flex) | flex, + vbox(summary), + separator() | color(colors::dark_gray), + render_navigation_bar(), + render_footer(), + }) | border | color(colors::kth_purple); } Element tui_dashboard::render_blockchain_screen() { @@ -526,7 +642,56 @@ Element tui_dashboard::render_mempool_screen() { } Element tui_dashboard::render_logs_screen() { - return render_placeholder("LOGS"); + Elements log_lines; + + if (status_.recent_logs.empty()) { + log_lines.push_back(text(" No logs yet...") | color(colors::gray) | dim); + } else { + // Show last N logs that fit + size_t const max_visible = 20; + size_t start = status_.recent_logs.size() > max_visible ? + status_.recent_logs.size() - max_visible : 0; + + for (size_t i = start; i < status_.recent_logs.size(); ++i) { + auto const& log = status_.recent_logs[i]; + + // Color based on log level (detect from content) + Color log_color = colors::white; + if (log.find("[error]") != std::string::npos || + log.find("[ERROR]") != std::string::npos || + log.find("Error") != std::string::npos) { + log_color = colors::red; + } else if (log.find("[warn]") != std::string::npos || + log.find("[WARN]") != std::string::npos || + log.find("Warning") != std::string::npos) { + log_color = colors::orange; + } else if (log.find("[info]") != std::string::npos || + log.find("[INFO]") != std::string::npos) { + log_color = colors::cyan; + } else if (log.find("[debug]") != std::string::npos || + log.find("[DEBUG]") != std::string::npos) { + log_color = colors::gray; + } + + // Truncate long lines + std::string display_log = log; + if (display_log.length() > 100) { + display_log = display_log.substr(0, 97) + "..."; + } + + log_lines.push_back(text(display_log) | color(log_color)); + } + } + + return vbox({ + render_header_bar(), + separator() | color(colors::dark_gray), + window(text(" 📋 LOGS ") | bold | color(colors::kth_violet), + vbox(log_lines) | flex) | flex, + separator() | color(colors::dark_gray), + render_navigation_bar(), + render_footer(), + }) | border | color(colors::kth_purple); } Element tui_dashboard::render_terminal_screen() { @@ -803,8 +968,9 @@ Element tui_dashboard::render_network_panel() { Elements rows; + // Header: Peers count and listen port rows.push_back(hbox({ - text("⬡ ") | color(total_peers > 0 ? colors::green : colors::red), + text("○ ") | color(total_peers > 0 ? colors::green : colors::red), text("Peers: ") | color(colors::gray), text(std::to_string(total_peers)) | bold | color(total_peers > 0 ? colors::green : colors::red), text(" (") | color(colors::dark_gray), @@ -813,31 +979,53 @@ Element tui_dashboard::render_network_panel() { text(")") | color(colors::dark_gray), })); - rows.push_back(text("")); - rows.push_back(hbox({ - text("↓ ") | color(colors::green) | bold, - text(format_bytes_speed(status_.bytes_received)) | color(colors::green), - text(" "), - text("↑ ") | color(colors::blue) | bold, - text(format_bytes_speed(status_.bytes_sent)) | color(colors::blue), + text("Listen: ") | color(colors::gray), + text(":8333") | color(colors::white), // TODO: get from config })); - if (status_.total_bytes_received > 0 || status_.total_bytes_sent > 0) { - rows.push_back(hbox({ - text("Total: ") | color(colors::gray), - text("↓" + format_bytes(status_.total_bytes_received)) | color(colors::green) | dim, - text(" ↑" + format_bytes(status_.total_bytes_sent)) | color(colors::blue) | dim, - })); - } + rows.push_back(text("")); - if (status_.avg_ping_ms > 0) { - rows.push_back(hbox({ - text("Ping: ") | color(colors::gray), - text(std::to_string(status_.avg_ping_ms) + "ms") | color( - status_.avg_ping_ms < 100 ? colors::green : - status_.avg_ping_ms < 500 ? colors::orange : colors::red), - })); + // Connected peers header + rows.push_back(text("Connected peers:") | color(colors::gray)); + + // Show each peer + if (status_.peers.empty()) { + rows.push_back(text(" (none)") | color(colors::dark_gray) | dim); + } else { + for (auto const& peer : status_.peers) { + // Direction + std::string direction = peer.is_inbound ? "IN " : "OUT"; + auto dir_color = peer.is_inbound ? colors::kth_violet : colors::cyan; + + // User agent - truncate if needed + std::string agent = peer.user_agent; + if (agent.empty()) agent = "Unknown"; + if (agent.length() > 12) agent = agent.substr(0, 12); + + // Format: OUT ip:port UserAgent H:height ↓recv ↑sent pingms + auto ping_color = peer.ping_ms == 0 ? colors::gray : + peer.ping_ms < 200 ? colors::green : + peer.ping_ms < 500 ? colors::orange : colors::red; + + auto ping_str = peer.ping_ms > 0 ? + std::to_string(peer.ping_ms) + "ms" : "-"; + + rows.push_back(hbox({ + text(direction + " ") | color(dir_color), + text(peer.address) | color(colors::white), + text(" "), + text(agent) | color(colors::cyan), + text(" "), + text("H:" + format_number(peer.start_height)) | color(colors::gray), + text(" "), + text("↓" + format_bytes(peer.bytes_received)) | color(colors::green), + text(" "), + text("↑" + format_bytes(peer.bytes_sent)) | color(colors::blue), + text(" "), + text(ping_str) | color(ping_color), + })); + } } return window(text(" ⚡ NETWORK ") | bold | color(colors::cyan), vbox(rows) | flex) | flex; diff --git a/src/node-exe/src/tui_dashboard.hpp b/src/node-exe/src/tui_dashboard.hpp index b6edbb76..7830876f 100644 --- a/src/node-exe/src/tui_dashboard.hpp +++ b/src/node-exe/src/tui_dashboard.hpp @@ -32,6 +32,19 @@ enum class screen_id { terminal, // C64-style terminal }; +/// Per-peer information for TUI display +struct peer_info { + std::string address; // IP:port + std::string user_agent; // Short user agent (e.g., "BCHN:28.0.1") + uint32_t start_height{0}; // Peer's reported height + size_t bytes_received{0}; // Total bytes received from peer + size_t bytes_sent{0}; // Total bytes sent to peer + uint32_t ping_ms{0}; // Last ping latency in ms + bool is_inbound{false}; // true if peer connected to us + bool is_preferred{false}; // true if preferred for download (BCHN fPreferredDownload) + std::chrono::seconds connected_duration{0}; // How long connected +}; + /// Node status for TUI display - Mining focused struct node_status { // Version & Network @@ -72,6 +85,9 @@ struct node_status { size_t total_bytes_sent{0}; // total bytes size_t avg_ping_ms{0}; + // Connected peers (for Network screen) + std::vector peers; + // Mempool size_t mempool_tx_count{0}; size_t mempool_size_bytes{0}; @@ -87,6 +103,9 @@ struct node_status { size_t db_cache_size{0}; double cpu_usage{0.0}; size_t memory_usage{0}; + + // Logs (for Logs screen) + std::vector recent_logs; }; /// TUI Dashboard using FTXUI - Multi-screen with animations @@ -106,6 +125,9 @@ class tui_dashboard { /// Update node status (thread-safe) void update_status(node_status const& status); + /// Add a log message (thread-safe) + void add_log(std::string const& message); + /// Check if TUI is running bool is_running() const; diff --git a/src/node/include/kth/node/executor/executor.hpp b/src/node/include/kth/node/executor/executor.hpp index 618fe4b0..f5a50f8d 100644 --- a/src/node/include/kth/node/executor/executor.hpp +++ b/src/node/include/kth/node/executor/executor.hpp @@ -6,8 +6,11 @@ #define KTH_NODE_EXE_EXECUTOR_HPP_ #include +#include +#include #include #include +#include #include #include @@ -18,121 +21,128 @@ #include #include +#include namespace kth::node { -struct executor { +/// Executor - manages the lifecycle of a full node +/// +/// The executor owns the io_context and runs it internally in its own thread. +/// This design allows the node to be used as a library from any language +/// (via C API) without the caller needing to manage async execution. +/// +/// Usage: +/// executor exec(config); +/// auto ec = exec.start(); // blocks until node is ready +/// // ... use node ... +/// exec.stop(); // blocks until node is stopped +/// +class executor { +public: + using start_handler = std::function; + using stop_handler = std::function; + executor(kth::node::configuration const& config, bool stdout_enabled = true); ~executor(); executor(executor const&) = delete; - void operator=(executor const&) = delete; + executor& operator=(executor const&) = delete; -#if ! defined(KTH_DB_READONLY) - bool do_initchain(std::string_view extra); -#endif + // ------------------------------------------------------------------------- + // Lifecycle - Async versions (callback-based, for C API and non-blocking use) + // ------------------------------------------------------------------------- -#if ! defined(KTH_DB_READONLY) - /// Initialize and run the node, blocking until signal or error - bool init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler); + /// Start the node asynchronously + /// @param handler Called when node is ready (or failed to start) + void start_async(start_handler handler); - /// Initialize and run the node without blocking - bool init_run(std::string_view extra, start_modules mod, kth::handle0 handler); -#endif + /// Stop the node asynchronously + /// @param handler Called when node is fully stopped (optional) + void stop_async(stop_handler handler = nullptr); - /// Signal the node to stop - void signal_stop(); + // ------------------------------------------------------------------------- + // Lifecycle - Sync versions (blocking, for simple use cases) + // ------------------------------------------------------------------------- - /// Stop and cleanup the node (must be called from main thread) - bool close(); + /// Start the node and block until ready + /// @return Error code (success if node started successfully) + [[nodiscard]] + code start(); - /// Access the full node - kth::node::full_node& node(); - kth::node::full_node const& node() const; + /// Stop the node and block until fully stopped + void stop(); + + /// Wait for stop signal (SIGINT/SIGTERM) + /// Blocks until signal received + void wait_for_stop_signal(); + + // ------------------------------------------------------------------------- + // State + // ------------------------------------------------------------------------- + + /// Check if node is currently running (started and not stopped) + [[nodiscard]] + bool running() const; + + /// Check if node has been started (may still be starting up) + [[nodiscard]] + bool started() const; /// Check if node is stopped + [[nodiscard]] bool stopped() const; - void print_version(std::string_view extra); - void initialize_output(std::string_view extra, kth::database::db_mode_type db_mode); + // ------------------------------------------------------------------------- + // Node access (only valid when running) + // ------------------------------------------------------------------------- + + [[nodiscard]] + kth::node::full_node& node(); + + [[nodiscard]] + kth::node::full_node const& node() const; + + // ------------------------------------------------------------------------- + // Initialization helpers + // ------------------------------------------------------------------------- #if ! defined(KTH_DB_READONLY) + bool do_initchain(std::string_view extra); bool init_directory(std::error_code& ec); std::error_code init_directory_if_necessary(); #endif bool verify_directory(); + void print_version(std::string_view extra); + void initialize_output(std::string_view extra, kth::database::db_mode_type db_mode); private: - bool wait_for_signal_and_close(); void print_ascii_art(); + void start_io_thread(); + void stop_io_thread(); - static - void stop(kth::code const& ec); - - static - void handle_stop(int code); - - void run_node_async(start_modules mod); - - // Termination state - static std::promise stopping_; - + // Configuration bool stdout_enabled_; kth::node::configuration config_; + + // Node instance kth::node::full_node::ptr node_; - kth::handle0 run_handler_; - // IO context for running coroutines + // IO context runs in its own thread ::asio::io_context io_context_; + using work_guard_type = ::asio::executor_work_guard<::asio::io_context::executor_type>; + std::optional work_guard_; std::thread io_thread_; - std::atomic running_{false}; -}; -// Localizable messages. -#define KTH_SETTINGS_MESSAGE "These are the configuration settings that can be set." -#define KTH_INFORMATION_MESSAGE "Runs a Bitcoin Cash full-node." -#define KTH_UNINITIALIZED_CHAIN "The {} directory is not initialized, run: kth --initchain" -#define KTH_INITIALIZING_CHAIN "Please wait while initializing {} directory..." -#define KTH_INITCHAIN_NEW "Failed to create directory {} with error, '{}'." -#define KTH_INITCHAIN_EXISTS "Failed because the directory {} already exists." -#define KTH_INITCHAIN_TRY "Failed to test directory {} with error, '{}'." -#define KTH_INITCHAIN_COMPLETE "Completed initialization." -#define KTH_INITCHAIN_FAILED "Error creating database files." - -#define KTH_NODE_INTERRUPT "Press CTRL-C to stop the node." -#define KTH_NODE_STARTING "Please wait while the node is starting..." -#define KTH_NODE_START_FAIL "Node failed to start with error, {}." -#define KTH_NODE_SEEDED "Seeding is complete." -#define KTH_NODE_STARTED "Node is started." - -#define KTH_NODE_SIGNALED "Stop signal detected (code: {})." -#define KTH_NODE_STOPPING "Please wait while the node is stopping..." -#define KTH_NODE_STOP_FAIL "Node failed to stop properly, see log." -#define KTH_NODE_STOPPED "Node stopped successfully." -#define KTH_GOOD_BYE "Good bye!" - -#define KTH_RPC_STOPPING "RPC-ZMQ service is stopping..." -#define KTH_RPC_STOPPED "RPC-ZMQ service stopped successfully" - -#define KTH_USING_CONFIG_FILE "Using config file: {}" -#define KTH_USING_DEFAULT_CONFIG "Using default configuration settings." - -#ifdef NDEBUG -#define KTH_VERSION_MESSAGE "Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}" -#else -#define KTH_VERSION_MESSAGE "Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}\n (Debug Build)" -#endif + // State tracking + enum class state { stopped, starting, running, stopping }; + std::atomic state_{state::stopped}; -#define KTH_VERSION_MESSAGE_INIT "Knuth v{}" -#define KTH_CRYPTOCURRENCY_INIT "Currency: {} - {}." -#define KTH_MICROARCHITECTURE_INIT "Optimized for microarchitecture: {}." -#define KTH_MARCH_EXTS_INIT "Built for CPU instructions/extensions: {}." -#define KTH_DB_TYPE_INIT "Database type: {}." -#define KTH_DEBUG_BUILD_INIT "(Debug Build)" -#define KTH_NETWORK_INIT "Network: {0} ({1} - {1:#x})." -#define KTH_BLOCKCHAIN_CORES_INIT "Blockchain configured to use {} threads." -#define KTH_NETWORK_CORES_INIT "Networking configured to use {} threads." + // Synchronization for sync versions + std::mutex start_mutex_; + std::condition_variable start_cv_; + code start_result_{error::success}; +}; } // namespace kth::node diff --git a/src/node/include/kth/node/full_node.hpp b/src/node/include/kth/node/full_node.hpp index 8b329a54..6d15d4c7 100644 --- a/src/node/include/kth/node/full_node.hpp +++ b/src/node/include/kth/node/full_node.hpp @@ -223,6 +223,7 @@ class KND_API full_node : public multi_crypto_setter { // Core components (composition, not inheritance) #if ! defined(__EMSCRIPTEN__) + kth::network::settings network_settings_; // Own copy, allows modification (e.g., user_agent) kth::network::p2p_node network_; #endif blockchain::block_chain chain_; diff --git a/src/node/include/kth/node/sync_session.hpp b/src/node/include/kth/node/sync_session.hpp index eebbb28e..3db6f8f0 100644 --- a/src/node/include/kth/node/sync_session.hpp +++ b/src/node/include/kth/node/sync_session.hpp @@ -113,11 +113,13 @@ class KND_API sync_session { using ptr = std::shared_ptr; /// Construct sync session + /// @param target_height Override target height (0 = use peer's start_height) sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, - sync_config const& config = {}); + sync_config const& config = {}, + size_t target_height = 0); /// Run synchronization with peer /// Returns when synced or on error @@ -164,12 +166,14 @@ class KND_API sync_session { }; /// Create a sync session for a peer +/// @param target_height Override target height (0 = use peer's start_height) [[nodiscard]] KND_API sync_session::ptr make_sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, - sync_config const& config = {}); + sync_config const& config = {}, + size_t target_height = 0); /// Run sync with the best available peer /// Selects peer based on start_height from version message diff --git a/src/node/src/executor/executor.cpp b/src/node/src/executor/executor.cpp index 76704801..40ca7d32 100644 --- a/src/node/src/executor/executor.cpp +++ b/src/node/src/executor/executor.cpp @@ -17,11 +17,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -45,284 +45,380 @@ using std::error_code; using kth::database::data_base; using std::placeholders::_1; -// static auto const application_name = "kth"; -static constexpr int initialize_stop = 0; static constexpr int directory_exists = 0; static constexpr int directory_not_found = 2; static auto const mode = std::ofstream::out | std::ofstream::app; -std::promise executor::stopping_; //NOLINT +// ============================================================================= +// Construction / Destruction +// ============================================================================= -executor::executor(kth::node::configuration const& config, bool stdout_enabled /*= true*/) +executor::executor(kth::node::configuration const& config, bool stdout_enabled) : stdout_enabled_(stdout_enabled) , config_(config) { #if ! defined(__EMSCRIPTEN__) - auto& network = config_.network; - auto const verbose = network.verbose; - - // Build user agent features list - std::vector features; -#if defined(KTH_CURRENCY_BCH) - features.push_back(format_eb(config_.chain.default_consensus_block_size)); -#endif - - network.user_agent = get_user_agent(features); - - kth::log::initialize(network.debug_file.string(), network.error_file.string(), stdout_enabled, verbose); + auto const& network = config_.network; + kth::log::initialize(network.debug_file.string(), network.error_file.string(), stdout_enabled, network.verbose); #endif // ! defined(__EMSCRIPTEN__) } executor::~executor() { - if (running_) { - signal_stop(); + // Ensure clean shutdown + if (state_.load() == state::running) { + stop(); } - // Ensure io_context is stopped and thread is joined +} + +// ============================================================================= +// IO Thread Management +// ============================================================================= + +void executor::start_io_thread() { + // Create work guard to keep io_context alive even when there's no work + work_guard_.emplace(io_context_.get_executor()); + + // Start io_context in background thread + io_thread_ = std::thread([this]() { + io_context_.run(); + }); +} + +void executor::stop_io_thread() { + // Release work guard to allow io_context to stop + work_guard_.reset(); + + // Stop io_context io_context_.stop(); + + // Wait for thread to finish if (io_thread_.joinable()) { io_thread_.join(); } } -void executor::print_version(std::string_view extra) { - std::println(KTH_VERSION_MESSAGE, kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); -} - -#if ! defined(KTH_DB_READONLY) -// TODO(fernando): This function inserts the genesis block directly into the DB, -// bypassing the blockchain layer (header_organizer/block_chain). When we implement -// persistence for header_index, we should reconsider this design - ideally genesis -// should be added through the same path as other headers for consistency. -bool executor::init_directory(error_code& ec) { - auto const& directory = config_.database.directory; +// ============================================================================= +// Async Lifecycle +// ============================================================================= - if (create_directories(directory, ec)) { - spdlog::info("[node] {}", fmt::format(KTH_INITIALIZING_CHAIN, directory.string())); +void executor::start_async(start_handler handler) { + auto expected = state::stopped; + if (!state_.compare_exchange_strong(expected, state::starting)) { + if (handler) { + handler(error::operation_failed); // Already started/starting/stopping + } + return; + } - auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); - auto const& settings = config_.database; + // Initialize output and directory + initialize_output("", config_.database.db_mode); - data_base db(settings); - auto const result = db.create(genesis); + spdlog::info("[node] Press CTRL-C to stop the node."); + spdlog::info("[node] Please wait while the node is starting..."); - if ( ! result ) { - spdlog::info("[node] {}", KTH_INITCHAIN_FAILED); - return false; +#if ! defined(KTH_DB_READONLY) + auto ec = init_directory_if_necessary(); + if (ec != error::success) { + auto const& directory = config_.database.directory; + spdlog::error("[node] Failed to create directory {} with error, '{}'.", directory.string(), ec.message()); + if (handler) { + handler(ec); } - - spdlog::info("[node] {}", KTH_INITCHAIN_COMPLETE); - return true; + return; } +#endif - return false; -} + // Create the node + node_ = std::make_shared(config_); -// CAPI -bool executor::do_initchain(std::string_view extra) { - initialize_output(extra, config_.database.db_mode); + // Start IO thread + start_io_thread(); - error_code ec; + // Spawn the startup coroutine + ::asio::co_spawn(io_context_, [this, handler]() -> ::asio::awaitable { + // Start the node + auto start_ec = co_await node_->start(); + if (start_ec != error::success) { + spdlog::error("[node] Node failed to start with error: {}.", start_ec.message()); + if (handler) { + handler(start_ec); + } + co_return; + } - if (init_directory(ec)) { - return true; - } + spdlog::info("[node] Seeding is complete."); - auto const& directory = config_.database.directory; + // Run the node (starts P2P, sync, etc.) + auto run_ec = co_await node_->run(); + if (run_ec != error::success) { + spdlog::error("[node] Node failed to start with error: {}.", run_ec.message()); + if (handler) { + handler(run_ec); + } + co_return; + } - if (ec.value() == directory_exists) { - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_EXISTS, directory.string())); - return false; - } + spdlog::info("[node] Node is started."); - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); - return false; -} + // Mark as running + state_ = state::running; -#endif // ! defined(KTH_DB_READONLY) + // Notify handler + if (handler) { + handler(error::success); + } -kth::node::full_node& executor::node() { - return *node_; + // Also notify sync version if waiting + { + std::lock_guard lock(start_mutex_); + start_result_ = error::success; + } + start_cv_.notify_all(); + + }, [this, handler](std::exception_ptr ep) { + if (ep) { + try { + std::rethrow_exception(ep); + } catch (std::exception const& e) { + spdlog::error("[node] Startup exception: {}", e.what()); + } + if (handler) { + handler(error::operation_failed); + } + // Notify sync version + { + std::lock_guard lock(start_mutex_); + start_result_ = error::operation_failed; + } + start_cv_.notify_all(); + } + }); } -kth::node::full_node const& executor::node() const { - return *node_; -} +void executor::stop_async(stop_handler handler) { + auto expected = state::running; + if (!state_.compare_exchange_strong(expected, state::stopping)) { + // Not running or already stopping + if (handler) { + handler(); + } + return; + } -// Close must be called from main thread. -bool executor::close() { - spdlog::info("[node] {}", KTH_NODE_STOPPING); + spdlog::info("[node] Please wait while the node is stopping..."); + // Stop node if (node_) { node_->stop(); - node_->join(); - spdlog::info("[node] {}", KTH_NODE_STOPPED); } - // Stop the io_context and wait for the io thread to finish - io_context_.stop(); - if (io_thread_.joinable()) { - io_thread_.join(); - } + // Spawn cleanup coroutine + ::asio::co_spawn(io_context_, [this, handler]() -> ::asio::awaitable { + // Wait for node to finish + if (node_) { + node_->join(); + } - spdlog::info("[node] {}", KTH_GOOD_BYE); - running_ = false; - return true; -} + spdlog::info("[node] Node stopped successfully."); + + state_ = state::stopped; -// private -bool executor::wait_for_signal_and_close() { - // Wait for stop. Ensure calling close from the main thread. - stopping_.get_future().wait(); - return close(); + if (handler) { + handler(); + } + + spdlog::info("[node] Good bye!"); + co_return; + }, ::asio::detached); } -#if ! defined(KTH_DB_READONLY) +// ============================================================================= +// Sync Lifecycle +// ============================================================================= -error_code executor::init_directory_if_necessary() { - if (verify_directory()) return error::success; +code executor::start() { + std::unique_lock lock(start_mutex_); - error_code ec; - if (init_directory(ec)) return error::success; + // Start async + start_async(nullptr); - return ec; + // Wait for completion + start_cv_.wait(lock, [this]() { + return state_.load() == state::running || start_result_ != error::success; + }); + + return start_result_; } -// Helper to run node in coroutine context -void executor::run_node_async(start_modules mod) { - ::asio::co_spawn(io_context_, [this, mod]() -> ::asio::awaitable { - // Start the node - auto start_ec = co_await node_->start(); - if (start_ec != error::success) { - spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, start_ec.message())); - if (run_handler_) { - run_handler_(start_ec); - } - co_return; - } +void executor::stop() { + if (state_.load() != state::running) { + return; + } - spdlog::info("[node] {}", KTH_NODE_SEEDED); - - // Run the node (only for full mode, not just_chain) - if (mod != start_modules::just_chain) { - auto run_ec = co_await node_->run(); - if (run_ec != error::success) { - spdlog::error("[node] {}", fmt::format(KTH_NODE_START_FAIL, run_ec.message())); - if (run_handler_) { - run_handler_(run_ec); - } - co_return; - } - } + std::promise done_promise; + auto done_future = done_promise.get_future(); + + stop_async([&done_promise]() { + done_promise.set_value(); + }); - spdlog::info("[node] {}", KTH_NODE_STARTED); + // Wait for stop to complete + done_future.wait(); - if (run_handler_) { - run_handler_(error::success); - } - }, ::asio::detached); + // Destroy node BEFORE stopping io_context + // (node's components use io_context for timer cancellation, etc.) + node_.reset(); - // Run the io_context in a background thread (saved for proper shutdown) - io_thread_ = std::thread([this]() { - io_context_.run(); - }); + // Stop IO thread + stop_io_thread(); } -bool executor::init_run_and_wait_for_signal(std::string_view extra, start_modules mod, kth::handle0 handler) { - run_handler_ = std::move(handler); +void executor::wait_for_stop_signal() { + std::promise signal_promise; + auto signal_future = signal_promise.get_future(); - initialize_output(extra, config_.database.db_mode); + // Use a separate io_context for signal handling + ::asio::io_context signal_context; + auto work_guard = ::asio::make_work_guard(signal_context); + ::asio::signal_set signals(signal_context, SIGINT, SIGTERM); - spdlog::info("[node] {}", KTH_NODE_INTERRUPT); - spdlog::info("[node] {}", KTH_NODE_STARTING); + signals.async_wait([&signal_promise, &work_guard](std::error_code const& ec, int signal_number) { + if (!ec) { + signal_promise.set_value(signal_number); + } + work_guard.reset(); // Allow io_context to stop + }); - auto ec = init_directory_if_necessary(); - if (ec != error::success) { - auto const& directory = config_.database.directory; - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); + // Run io_context in background thread + std::thread signal_thread([&signal_context]() { + signal_context.run(); + }); - if (run_handler_) { - run_handler_(ec); - } - auto res = wait_for_signal_and_close(); - return false; + // Wait for signal + auto signal_received = signal_future.get(); + spdlog::info("[node] Stop signal detected (code: {}).", signal_received); + + // Cleanup + if (signal_thread.joinable()) { + signal_thread.join(); } +} - // Now that the directory is verified we can create the node for it. - node_ = std::make_shared(config_); - running_ = true; +// ============================================================================= +// State +// ============================================================================= - // Start and run the node asynchronously - run_node_async(mod); +bool executor::running() const { + return state_.load() == state::running; +} - auto res = wait_for_signal_and_close(); - return res; +bool executor::started() const { + auto s = state_.load(); + return s == state::starting || s == state::running || s == state::stopping; } -bool executor::init_run(std::string_view extra, start_modules mod, kth::handle0 handler) { - run_handler_ = std::move(handler); +bool executor::stopped() const { + return state_.load() == state::stopped; +} - initialize_output(extra, config_.database.db_mode); +// ============================================================================= +// Node Access +// ============================================================================= - spdlog::info("[node] {}", KTH_NODE_INTERRUPT); - spdlog::info("[node] {}", KTH_NODE_STARTING); +kth::node::full_node& executor::node() { + return *node_; +} - auto ec = init_directory_if_necessary(); - if (ec != error::success) { - auto const& directory = config_.database.directory; - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_NEW, directory.string(), ec.message())); +kth::node::full_node const& executor::node() const { + return *node_; +} - if (run_handler_) { - run_handler_(ec); - } - return false; - } +// ============================================================================= +// Initialization Helpers +// ============================================================================= - // Now that the directory is verified we can create the node for it. - node_ = std::make_shared(config_); - running_ = true; +#if ! defined(KTH_DB_READONLY) +bool executor::init_directory(error_code& ec) { + auto const& directory = config_.database.directory; - // Start and run the node asynchronously - run_node_async(mod); + if (create_directories(directory, ec)) { + spdlog::info("[node] Please wait while initializing {} directory...", directory.string()); - return true; -} + auto const genesis = kth::node::full_node::get_genesis_block(get_network(config_.network.identifier, config_.network.inbound_port == 48333)); + auto const& settings = config_.database; -#endif // ! defined(KTH_DB_READONLY) + data_base db(settings); + auto const result = db.create(genesis); -bool executor::stopped() const { - return node_ ? node_->stopped() : true; + if (!result) { + spdlog::info("[node] Error creating database files."); + return false; + } + + spdlog::info("[node] Completed initialization."); + return true; + } + + return false; } -// Stop signal. -// ---------------------------------------------------------------------------- +bool executor::do_initchain(std::string_view extra) { + initialize_output(extra, config_.database.db_mode); -void executor::handle_stop(int code) { - // Reinitialize after each capture to prevent hard shutdown. - // Do not capture failure signals as calling stop can cause flush lock file - // to clear due to the aborted thread dropping the flush lock mutex. - std::signal(SIGINT, handle_stop); - std::signal(SIGTERM, handle_stop); + error_code ec; - if (code == initialize_stop) { - return; + if (init_directory(ec)) { + return true; + } + + auto const& directory = config_.database.directory; + + if (ec.value() == directory_exists) { + spdlog::error("[node] Failed because the directory {} already exists.", directory.string()); + return false; } - spdlog::info("[node] {}", fmt::format(KTH_NODE_SIGNALED, code)); - stop(kth::error::success); + spdlog::error("[node] Failed to create directory {} with error, '{}'.", directory.string(), ec.message()); + return false; } -void executor::signal_stop() { - stop(kth::code()); +error_code executor::init_directory_if_necessary() { + if (verify_directory()) return error::success; + + error_code ec; + if (init_directory(ec)) return error::success; + + return ec; } +#endif // ! defined(KTH_DB_READONLY) -// Manage the race between console stop and server stop. -void executor::stop(kth::code const& ec) { - static std::once_flag stop_mutex; - std::call_once(stop_mutex, [&](){ stopping_.set_value(ec); }); +bool executor::verify_directory() { + error_code ec; + auto const& directory = config_.database.directory; + + if (exists(directory, ec)) { + return true; + } + + if (ec.value() == directory_not_found) { + spdlog::error("[node] The {} directory is not initialized, run: kth --initchain", directory.string()); + return false; + } + + auto const message = ec.message(); + spdlog::error("[node] Failed to test directory {} with error, '{}'.", directory.string(), message); + return false; } -// Utilities. -// ---------------------------------------------------------------------------- +void executor::print_version(std::string_view extra) { +#ifdef NDEBUG + std::println("Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}", + kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); +#else + std::println("Knuth Node\n C++ lib v{}\n {}\n Currency: {}\n Microarchitecture: {}\n Built for CPU instructions/extensions: {}\n (Debug Build)", + kth::version, extra, KTH_CURRENCY_SYMBOL_STR, KTH_MICROARCHITECTURE_STR, march_names()); +#endif +} void executor::print_ascii_art() { std::print(R"( ... @@ -344,7 +440,6 @@ void executor::print_ascii_art() { High Performance Bitcoin Cash Node )"); - // Center version under the slogan constexpr char slogan[] = "High Performance Bitcoin Cash Node"; constexpr auto slogan_start = 10; auto version_text = std::format("v{}", kth::version); @@ -353,7 +448,6 @@ void executor::print_ascii_art() { std::println(); } -// Set up logging. void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { auto const& file = config_.file; @@ -362,9 +456,9 @@ void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { } if (file.empty()) { - spdlog::info("[node] {}", KTH_USING_DEFAULT_CONFIG); + spdlog::info("[node] Using default configuration settings."); } else { - spdlog::info("[node] {}", fmt::format(KTH_USING_CONFIG_FILE, file.string())); + spdlog::info("[node] Using config file: {}", file.string()); } std::string_view db_type_str; @@ -376,38 +470,21 @@ void executor::initialize_output(std::string_view extra, db_mode_type db_mode) { db_type_str = KTH_DB_TYPE_PRUNED; } - spdlog::info("[node] {}", fmt::format(KTH_VERSION_MESSAGE_INIT, kth::version)); - spdlog::info("[node] {}", fmt::format(KTH_CRYPTOCURRENCY_INIT, KTH_CURRENCY_SYMBOL_STR, KTH_CURRENCY_STR)); - spdlog::info("[node] {}", fmt::format(KTH_MICROARCHITECTURE_INIT, KTH_MICROARCHITECTURE_STR)); - spdlog::info("[node] {}", fmt::format(KTH_MARCH_EXTS_INIT, march_names())); - spdlog::info("[node] {}", fmt::format(KTH_DB_TYPE_INIT, db_type_str)); + spdlog::info("[node] Knuth v{}", kth::version); + spdlog::info("[node] Currency: {} - {}.", KTH_CURRENCY_SYMBOL_STR, KTH_CURRENCY_STR); + spdlog::info("[node] Optimized for microarchitecture: {}.", KTH_MICROARCHITECTURE_STR); + spdlog::info("[node] Built for CPU instructions/extensions: {}.", march_names()); + spdlog::info("[node] Database type: {}.", db_type_str); #ifndef NDEBUG - spdlog::info("[node] {}", KTH_DEBUG_BUILD_INIT); + spdlog::info("[node] (Debug Build)"); #endif - spdlog::info("[node] {}", fmt::format(KTH_NETWORK_INIT, name(kth::get_network(config_.network.identifier, config_.network.inbound_port == 48333)), config_.network.identifier)); - spdlog::info("[node] {}", fmt::format(KTH_BLOCKCHAIN_CORES_INIT, kth::thread_ceiling(config_.chain.cores))); - spdlog::info("[node] {}", fmt::format(KTH_NETWORK_CORES_INIT, kth::thread_ceiling(config_.network.threads))); -} - -// Use missing directory as a sentinel indicating lack of initialization. -bool executor::verify_directory() { - error_code ec; - auto const& directory = config_.database.directory; - - if (exists(directory, ec)) { - return true; - } - - if (ec.value() == directory_not_found) { - spdlog::error("[node] {}", fmt::format(KTH_UNINITIALIZED_CHAIN, directory.string())); - return false; - } - - auto const message = ec.message(); - spdlog::error("[node] {}", fmt::format(KTH_INITCHAIN_TRY, directory.string(), message)); - return false; + auto const network_id = config_.network.identifier; + auto const network_type = kth::get_network(network_id, config_.network.inbound_port == 48333); + spdlog::info("[node] Network: {0} ({1} - {1:#x}).", name(network_type), network_id); + spdlog::info("[node] Blockchain configured to use {} threads.", kth::thread_ceiling(config_.chain.cores)); + spdlog::info("[node] Networking configured to use {} threads.", kth::thread_ceiling(config_.network.threads)); } } // namespace kth::node diff --git a/src/node/src/full_node.cpp b/src/node/src/full_node.cpp index 2d207ea2..26f26699 100644 --- a/src/node/src/full_node.cpp +++ b/src/node/src/full_node.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,8 @@ full_node::full_node(configuration const& configuration) , chain_settings_(configuration.chain) , network_type_(get_network(configuration.network.identifier, configuration.network.inbound_port == 48333)) , chain_thread_pool_(configuration.chain.cores) - , network_(configuration.network) + , network_settings_(configuration.network) + , network_(network_settings_) , chain_( chain_thread_pool_, configuration.chain, @@ -61,11 +63,23 @@ full_node::full_node(configuration const& configuration) network_type_ ) #endif -{} +{ +#if ! defined(__EMSCRIPTEN__) + // Set user agent after initialization (network_ holds reference to network_settings_) + std::vector features; +#if defined(KTH_CURRENCY_BCH) + features.push_back(format_eb(configuration.chain.default_consensus_block_size)); +#endif + network_settings_.user_agent = get_user_agent(features); +#endif +} full_node::~full_node() { - stop(); - join(); + // Only stop/join if not already stopped + if (!stopped()) { + stop(); + join(); + } } // ============================================================================= diff --git a/src/node/src/sync_session.cpp b/src/node/src/sync_session.cpp index 167b2bcd..c073af1a 100644 --- a/src/node/src/sync_session.cpp +++ b/src/node/src/sync_session.cpp @@ -27,7 +27,8 @@ sync_session::sync_session( block_chain& chain, peer_session::ptr peer, domain::config::network network, - sync_config const& config) + sync_config const& config, + size_t target_height) : chain_(chain) , organizer_(chain.headers(), chain.chain_settings(), network) , peer_(std::move(peer)) @@ -40,10 +41,14 @@ sync_session::sync_session( block_height_ = heights->second; // block-sync height } - // Get target height from peer's version message - auto peer_version = peer_->peer_version(); - if (peer_version) { - target_height_ = peer_version->start_height(); + // Use provided target height if given, otherwise use peer's start_height + if (target_height > 0) { + target_height_ = target_height; + } else { + auto peer_version = peer_->peer_version(); + if (peer_version) { + target_height_ = peer_version->start_height(); + } } // Get hash of current header tip (for getheaders locator) @@ -66,9 +71,10 @@ sync_session::ptr make_sync_session( block_chain& chain, peer_session::ptr peer, domain::config::network network, - sync_config const& config) + sync_config const& config, + size_t target_height) { - return std::make_shared(chain, peer, network, config); + return std::make_shared(chain, peer, network, config, target_height); } // ============================================================================= @@ -624,8 +630,18 @@ ::asio::awaitable sync_from_best_peer( } } - spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), our height: {}", - peers.size(), preferred_count, full_node_count, our_block_height); + // Calculate max height across all peers (BCHN-style) + // Don't trust just one peer's reported height + size_t max_peer_height = 0; + for (auto const& peer : peers) { + auto version = peer->peer_version(); + if (version) { + max_peer_height = std::max(max_peer_height, size_t(version->start_height())); + } + } + + spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), our height: {}, max peer height: {}", + peers.size(), preferred_count, full_node_count, our_block_height, max_peer_height); // Select best peer using BCHN logic auto best_peer = select_sync_peer(peers, our_block_height); @@ -640,12 +656,12 @@ ::asio::awaitable sync_from_best_peer( auto version = best_peer->peer_version(); auto const best_height = version ? version->start_height() : 0; - spdlog::info("[sync] Selected {} peer [{}] with height {} for sync", + spdlog::info("[sync] Selected {} peer [{}] with height {} for sync (target: {})", best_peer->is_preferred_download() ? "preferred" : "fallback", - best_peer->authority(), best_height); + best_peer->authority(), best_height, max_peer_height); - // Run sync with selected peer - auto session = make_sync_session(chain, best_peer, network, config); + // Run sync with selected peer, using max_peer_height as target + auto session = make_sync_session(chain, best_peer, network, config, max_peer_height); result = co_await session->run(); // BCHN-style: If sync failed (including timeout), try another peer @@ -683,12 +699,12 @@ ::asio::awaitable sync_from_best_peer( ++retry; version = retry_peer->peer_version(); auto const retry_height = version ? version->start_height() : 0; - spdlog::info("[sync] Retry {}: {} peer [{}] height {}", + spdlog::info("[sync] Retry {}: {} peer [{}] height {} (target: {})", retry, retry_peer->is_preferred_download() ? "preferred" : "fallback", - retry_peer->authority(), retry_height); + retry_peer->authority(), retry_height, max_peer_height); - auto retry_session = make_sync_session(chain, retry_peer, network, config); + auto retry_session = make_sync_session(chain, retry_peer, network, config, max_peer_height); result = co_await retry_session->run(); if (!result.error) { From 7cc1966ce3376329fb4523e92a3e112cac79a231 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 25 Dec 2025 17:53:11 +0100 Subject: [PATCH 13/14] feat(network): implement structured concurrency with task_group and peer_supervisor Replace detached coroutines with structured concurrency patterns: - Add task_group utility for managing parallel coroutines with automatic cleanup - Implement peer_supervisor as a nursery that manages peer lifecycles - Use concurrent_channel for peer events instead of fire-and-forget spawns - Add supervisor_ready_ atomic for deterministic synchronization - Close response channels (headers_responses_, block_responses_) on peer stop to properly propagate shutdown to waiting sync operations - Modernize executor with internal io_context and graceful shutdown - Fix thread_ceiling to use all cores when threads=0 Key changes: - p2p_node::run() now uses task_group instead of co_spawn with detached - peer_supervisor tracks all peer tasks and waits for completion on shutdown - Clean shutdown: all coroutines complete orderly, "Good bye!" prints reliably - Manual peer connections wait for supervisor_ready_ before connecting --- .../include/kth/infrastructure.hpp | 2 + .../kth/infrastructure/utility/task_group.hpp | 218 +++++++ src/network/include/kth/network/p2p_node.hpp | 36 ++ .../include/kth/network/peer_session.hpp | 33 + .../include/kth/network/protocols_coro.hpp | 17 + src/network/src/p2p_node.cpp | 588 +++++++++++------- src/network/src/peer_manager.cpp | 15 +- src/network/src/peer_session.cpp | 81 ++- src/network/src/protocols_coro.cpp | 126 ++++ src/network/src/settings.cpp | 4 +- src/node-exe/src/main.cpp | 45 +- src/node/include/kth/node/full_node.hpp | 6 + src/node/src/executor/executor.cpp | 95 +-- src/node/src/full_node.cpp | 152 +++-- 14 files changed, 1083 insertions(+), 335 deletions(-) create mode 100644 src/infrastructure/include/kth/infrastructure/utility/task_group.hpp diff --git a/src/infrastructure/include/kth/infrastructure.hpp b/src/infrastructure/include/kth/infrastructure.hpp index 17ffb776..389564ef 100644 --- a/src/infrastructure/include/kth/infrastructure.hpp +++ b/src/infrastructure/include/kth/infrastructure.hpp @@ -112,6 +112,8 @@ #include #include #include +#include +#include #include #include diff --git a/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp new file mode 100644 index 00000000..df381ae3 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp @@ -0,0 +1,218 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_TASK_GROUP_HPP +#define KTH_INFRASTRUCTURE_TASK_GROUP_HPP + +#include +#include +#include +#include + +#include +#include + +namespace kth { + +// ============================================================================= +// Task Group (Nursery Pattern for Structured Concurrency) +// ============================================================================= +// +// A task_group manages a set of concurrent coroutines and ensures all complete +// before the group is destroyed. This implements the "nursery" pattern from +// structured concurrency (similar to Trio in Python or Kotlin coroutines). +// +// Key properties: +// - All spawned tasks are tracked automatically +// - join() waits for ALL tasks to complete +// - No tasks are "lost" or detached +// - Exception in any task can be propagated (future enhancement) +// +// Usage: +// task_group tasks(executor); +// +// tasks.spawn([&]() -> awaitable { +// co_await do_work_1(); +// }); +// +// tasks.spawn([&]() -> awaitable { +// co_await do_work_2(); +// }); +// +// co_await tasks.join(); // Waits for both tasks +// +// Integration with structured concurrency: +// awaitable parent_task() { +// task_group children(co_await this_coro::executor); +// +// children.spawn(child_1()); +// children.spawn(child_2()); +// +// co_await children.join(); // Parent waits for all children +// } +// +// ============================================================================= + +class task_group { +public: + explicit task_group(::asio::any_io_executor executor) + : executor_(std::move(executor)) + , done_channel_(executor_, 1) + {} + + // Non-copyable, non-movable (prevents accidental misuse) + task_group(task_group const&) = delete; + task_group& operator=(task_group const&) = delete; + task_group(task_group&&) = delete; + task_group& operator=(task_group&&) = delete; + + ~task_group() { + // In debug builds, assert that join() was called + // In release, just log a warning if tasks are still active + if (active_count_.load() > 0) { + // Tasks still running - this is a programming error + // The destructor should only be called after join() + } + } + + // Spawn a coroutine into the group. + // The coroutine will be tracked and join() will wait for it. + // Note: This uses ONE internal detached spawn, but the task is tracked. + template + void spawn(Coro&& coro) { + ++active_count_; + ++total_spawned_; + + ::asio::co_spawn(executor_, + [this, c = std::forward(coro)]() mutable -> ::asio::awaitable { + try { + co_await std::invoke(std::move(c)); + } catch (...) { + // TODO: Store exception for later propagation + // For now, just decrement and signal + } + decrement_and_signal(); + }, + ::asio::detached); // Single controlled detached point + } + + // Wait for all spawned tasks to complete. + // This MUST be called before the task_group is destroyed. + [[nodiscard]] + ::asio::awaitable join() { + if (active_count_.load() == 0) { + co_return; + } + + // Wait for signal that all tasks completed + auto [ec] = co_await done_channel_.async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + // Channel closed or received signal - all tasks done + co_return; + } + + // Check if there are active tasks + [[nodiscard]] + bool has_active_tasks() const noexcept { + return active_count_.load() > 0; + } + + // Get number of currently active tasks + [[nodiscard]] + size_t active_count() const noexcept { + return active_count_.load(); + } + + // Get total number of tasks spawned (including completed) + [[nodiscard]] + size_t total_spawned() const noexcept { + return total_spawned_.load(); + } + +private: + void decrement_and_signal() { + auto const prev = active_count_.fetch_sub(1); + if (prev == 1) { + // We were the last task - signal completion + // Use try_send to avoid blocking if no one is waiting yet + done_channel_.try_send(std::error_code{}); + } + } + + ::asio::any_io_executor executor_; + std::atomic active_count_{0}; + std::atomic total_spawned_{0}; + + // Channel to signal when all tasks complete + // Capacity of 1 is sufficient - we only send once when count hits 0 + concurrent_event_channel done_channel_; +}; + +// ============================================================================= +// Scoped Task Group (RAII wrapper) +// ============================================================================= +// +// Automatically joins on scope exit. Useful for ensuring structured concurrency +// even when exceptions occur. +// +// Usage: +// { +// scoped_task_group tasks(executor); +// tasks.spawn(work_1()); +// tasks.spawn(work_2()); +// } // Automatically waits here (blocking!) +// +// WARNING: The destructor blocks! Use with care. +// Prefer explicit co_await join() in coroutines. +// +// ============================================================================= + +class scoped_task_group { +public: + explicit scoped_task_group(::asio::any_io_executor executor) + : executor_(executor) + , group_(std::move(executor)) + {} + + ~scoped_task_group() { + if (group_.has_active_tasks()) { + // Block until all tasks complete + // This is a blocking call - use sparingly! + std::promise done; + auto future = done.get_future(); + + ::asio::co_spawn(executor_, + [this, &done]() -> ::asio::awaitable { + co_await group_.join(); + done.set_value(); + }, + ::asio::detached); + + future.wait(); + } + } + + template + void spawn(Coro&& coro) { + group_.spawn(std::forward(coro)); + } + + [[nodiscard]] + ::asio::awaitable join() { + return group_.join(); + } + + [[nodiscard]] size_t active_count() const noexcept { + return group_.active_count(); + } + +private: + ::asio::any_io_executor executor_; + task_group group_; +}; + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_TASK_GROUP_HPP diff --git a/src/network/include/kth/network/p2p_node.hpp b/src/network/include/kth/network/p2p_node.hpp index cd41dd22..5c2d132b 100644 --- a/src/network/include/kth/network/p2p_node.hpp +++ b/src/network/include/kth/network/p2p_node.hpp @@ -133,6 +133,31 @@ struct connection_result { handshake_result handshake; }; +// ============================================================================= +// Peer event (for peer_supervisor channel) +// ============================================================================= + +enum class peer_direction { + inbound, + outbound +}; + +/// Result of handshake sent back to connect() caller +struct handshake_response { + code result; // error::success or error code +}; + +/// Channel type for handshake response (one-shot) +using handshake_response_channel = concurrent_channel; + +struct peer_event { + peer_session::ptr peer; + peer_direction direction; + // Optional response channel for connect() to wait on handshake result + // If nullptr, no response is expected (e.g., for seeding connections) + std::shared_ptr response_channel; +}; + // ============================================================================= // P2P Node (main networking class) // ============================================================================= @@ -235,6 +260,9 @@ class KN_API p2p_node { ::asio::awaitable run_peer_protocols(peer_session::ptr peer); ::asio::awaitable maintain_outbound_connections(); + // Peer supervisor - manages all peer lifecycles (structured concurrency) + ::asio::awaitable peer_supervisor(); + // Helper for seeding - takes params by value to avoid lambda capture issues ::asio::awaitable connect_to_seed( std::string seed_host, @@ -253,10 +281,18 @@ class KN_API p2p_node { std::atomic stopped_{true}; std::atomic seeded_{false}; + std::atomic supervisor_ready_{false}; // Signals that peer_supervisor is ready kth::atomic top_block_; // Message dispatcher for routing messages to handlers message_dispatcher dispatcher_; + + // Channels for structured concurrency (peer_supervisor pattern) + // New peers are sent here by run_inbound/run_outbound, processed by peer_supervisor + std::unique_ptr> new_peer_channel_; + + // Signal to stop the peer_supervisor gracefully + std::unique_ptr stop_signal_; }; } // namespace kth::network diff --git a/src/network/include/kth/network/peer_session.hpp b/src/network/include/kth/network/peer_session.hpp index 56c03a32..29e004a8 100644 --- a/src/network/include/kth/network/peer_session.hpp +++ b/src/network/include/kth/network/peer_session.hpp @@ -126,6 +126,39 @@ class KN_API peer_session : public std::enable_shared_from_this { [[nodiscard]] inbound_channel& messages(); + // ------------------------------------------------------------------------- + // Direct I/O (for handshake before run() starts) + // ------------------------------------------------------------------------- + // These methods read/write directly to the socket without using channels. + // Use ONLY before calling run() - after run() starts, use send() and messages(). + + /// Read a message directly from the socket (bypasses inbound channel) + /// Use this for handshake before run() is started + [[nodiscard]] + awaitable_expected read_message_direct(); + + /// Send a message directly to the socket (bypasses outbound channel) + /// Use this for handshake before run() is started + template + ::asio::awaitable send_direct(Message const& message) { + if (stopped()) { + co_return error::channel_stopped; + } + + auto data = domain::message::serialize(version_.load(), message, protocol_magic_); + auto [ec, bytes_written] = co_await ::asio::async_write( + socket_, + ::asio::buffer(data), + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + co_return error::boost_to_error_code(ec); + } + + bytes_sent_.fetch_add(bytes_written, std::memory_order_relaxed); + co_return error::success; + } + // ------------------------------------------------------------------------- // Response channels (for request/response patterns like getheaders/headers) // ------------------------------------------------------------------------- diff --git a/src/network/include/kth/network/protocols_coro.hpp b/src/network/include/kth/network/protocols_coro.hpp index 98d80eb2..a5d6c6d3 100644 --- a/src/network/include/kth/network/protocols_coro.hpp +++ b/src/network/include/kth/network/protocols_coro.hpp @@ -167,6 +167,23 @@ KN_API awaitable_expected perform_handshake( peer_session& peer, handshake_config const& config); +/// Perform version handshake using direct socket I/O (no message pump needed) +/// This version reads/writes directly to the socket, so peer->run() does NOT +/// need to be running. Use this to avoid detached coroutines in connect/accept. +/// +/// Usage: +/// auto peer = co_await async_connect(...); +/// auto result = co_await perform_handshake_direct(*peer, config); // No run() needed! +/// // After handshake, send peer to supervisor which starts run() +/// +/// @param peer The peer session (run() must NOT be running yet) +/// @param config Handshake configuration +/// @return handshake_result on success, error code on failure +[[nodiscard]] +KN_API awaitable_expected perform_handshake_direct( + peer_session& peer, + handshake_config const& config); + /// Create handshake config from network settings [[nodiscard]] KN_API handshake_config make_handshake_config( diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp index 0645c472..836f7372 100644 --- a/src/network/src/p2p_node.cpp +++ b/src/network/src/p2p_node.cpp @@ -21,17 +21,18 @@ using namespace std::chrono_literals; p2p_node::p2p_node(settings const& settings) : settings_(settings) - , pool_(settings.threads > 0 ? settings.threads : 1) + , pool_(thread_ceiling(settings.threads)) // 0 means use all cores , manager_(pool_.get_executor()) , hosts_(settings) , top_block_({null_hash, 0}) + , new_peer_channel_(std::make_unique>(pool_.get_executor(), 100)) + , stop_signal_(std::make_unique(pool_.get_executor(), 1)) { - spdlog::debug("[p2p_node] p2p_node constructor - member init complete"); + spdlog::debug("[p2p_node] p2p_node constructor - thread pool size: {}", pool_.size()); // Register default message handlers using typed registration // The make_handler<> wrapper handles parsing automatically dispatcher_.register_handler(handlers::ping::handle); dispatcher_.register_handler(handlers::pong::handle); - spdlog::debug("[p2p_node] p2p_node constructor completed successfully"); } p2p_node::~p2p_node() { @@ -59,25 +60,63 @@ ::asio::awaitable p2p_node::start() { } ::asio::awaitable p2p_node::run() { + spdlog::debug("[p2p_node] run() starting"); + if (stopped_) { + spdlog::debug("[p2p_node] run() - already stopped"); co_return error::service_stopped; } - // Start inbound acceptor - ::asio::co_spawn(pool_.get_executor(), run_inbound(), ::asio::detached); - - // Start outbound connection manager - ::asio::co_spawn(pool_.get_executor(), run_outbound(), ::asio::detached); + // Run all network tasks in parallel using task_group on pool_ executor. + // We use task_group instead of && operator because && runs all coroutines + // on the caller's executor (which may be single-threaded). task_group + // uses pool_.get_executor() which has multiple threads, allowing true + // parallelism and proper coroutine scheduling. + task_group network_tasks(pool_.get_executor()); + + spdlog::debug("[p2p_node] Spawning peer_supervisor..."); + network_tasks.spawn([this]() -> ::asio::awaitable { + spdlog::debug("[p2p_node] peer_supervisor coroutine starting"); + co_await peer_supervisor(); + spdlog::debug("[p2p_node] peer_supervisor coroutine finished"); + }); + + spdlog::debug("[p2p_node] Spawning run_inbound..."); + network_tasks.spawn([this]() -> ::asio::awaitable { + spdlog::debug("[p2p_node] run_inbound coroutine starting"); + co_await run_inbound(); + spdlog::debug("[p2p_node] run_inbound coroutine finished"); + }); + + spdlog::debug("[p2p_node] Spawning run_outbound..."); + network_tasks.spawn([this]() -> ::asio::awaitable { + spdlog::debug("[p2p_node] run_outbound coroutine starting"); + co_await run_outbound(); + spdlog::debug("[p2p_node] run_outbound coroutine finished"); + }); + + // Wait for supervisor to be ready before connecting manual peers + while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { + co_await ::asio::post(pool_.get_executor(), ::asio::use_awaitable); + } - // Connect to configured manual peers - for (auto const& peer : settings_.peers) { - auto result = co_await connect(peer.host(), peer.port()); - if (!result) { - spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", - peer.host(), peer.port(), result.error().message()); + // Connect to configured manual peers (supervisor is now ready) + if (!settings_.peers.empty()) { + spdlog::debug("[p2p_node] run() - connecting to {} manual peers", settings_.peers.size()); + for (auto const& peer : settings_.peers) { + auto result = co_await connect(peer.host(), peer.port()); + if (!result) { + spdlog::warn("[p2p_node] Failed to connect to configured peer {}:{} - {}", + peer.host(), peer.port(), result.error().message()); + } } } + spdlog::debug("[p2p_node] All tasks spawned, waiting on join..."); + // Wait for all tasks to complete (i.e., until stop() is called) + co_await network_tasks.join(); + spdlog::debug("[p2p_node] All tasks completed"); + co_return error::success; } @@ -87,20 +126,38 @@ void p2p_node::stop() { } stopped_ = true; + supervisor_ready_ = false; // Reset for potential restart + + // Close stop_signal_ channel - this wakes up ALL waiters (peer_supervisor, + // maintain_outbound_connections) because async_receive returns error when closed + if (stop_signal_) { + stop_signal_->close(); + } - // Stop acceptor + // Close the new peer channel to wake up peer_supervisor + if (new_peer_channel_) { + new_peer_channel_->close(); + } + + // Stop acceptor - this causes run_inbound() to exit if (acceptor_) { std::error_code ec; acceptor_->close(ec); } - // Stop all peers + // Stop all peers - this causes peer->run() to exit, which allows + // peer_supervisor's peer_tasks.join() to complete manager_.stop_all(); // hosts_ saves to file in destructor - // Stop thread pool - pool_.stop(); + // NOTE: We do NOT call pool_.stop() here! + // With structured concurrency, all coroutines will complete naturally: + // 1. run_inbound() exits (acceptor closed) + // 2. run_outbound() exits (stopped_ = true) + // 3. peer_supervisor() exits after peer_tasks.join() completes + // 4. run() returns, then join() can complete + // Calling pool_.stop() here would abort pending work and prevent clean shutdown. } void p2p_node::join() { @@ -251,47 +308,37 @@ awaitable_expected p2p_node::connect( co_return std::unexpected(error::address_blocked); } - // Start the session's message pump - ::asio::co_spawn(executor, peer->run(), ::asio::detached); - - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - - // Perform handshake - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { + // Create response channel for handshake result + auto response_channel = std::make_shared(executor, 1); + + // Send peer to supervisor for FULL lifecycle management (structured concurrency) + // The supervisor will do: peer->run() && (handshake && protocols) + // This eliminates the need for detached coroutines entirely! + if (new_peer_channel_ && new_peer_channel_->is_open()) { + co_await new_peer_channel_->async_send( + std::error_code{}, + peer_event{peer, peer_direction::outbound, response_channel}, + ::asio::use_awaitable); + } else { peer->stop(); - spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", - host, port, handshake_result.error().message()); - co_return std::unexpected(handshake_result.error()); + co_return std::unexpected(error::service_stopped); } - spdlog::info("[p2p_node] Handshake complete with {}:{}, version {}, {}", - host, port, handshake_result->negotiated_version, - handshake_result->peer_version->user_agent()); - - // Send initial ping immediately to get latency data quickly (like BCHN) - { - uint64_t nonce = 0; - pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); - domain::message::ping ping_msg(nonce); - auto ec = co_await peer->send(ping_msg); - if (ec == error::success) { - peer->record_ping_sent(nonce); - } - } + // Wait for supervisor to complete handshake and send result + auto [recv_ec, response] = co_await response_channel->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); - // Add to peer manager - auto ec = co_await manager_.add(peer); - if (ec != error::success) { - peer->stop(); - co_return std::unexpected(ec); + if (recv_ec || response.result != error::success) { + // Handshake failed - peer is already stopped by supervisor + auto err = recv_ec ? error::channel_stopped : response.result; + spdlog::debug("[p2p_node] Handshake failed with {}:{} - {}", + host, port, err.message()); + co_return std::unexpected(err); } - // Start protocol handlers - ::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); + spdlog::info("[p2p_node] Connection complete with {}:{}, version {}, {}", + host, port, peer->negotiated_version(), + peer->peer_version()->user_agent()); co_return peer; } @@ -336,57 +383,47 @@ std::vector p2p_node::get_peers() const { ::asio::awaitable p2p_node::run_seeding() { spdlog::info("[p2p_node] Starting seeding from {} seeds", settings_.seeds.size()); - spdlog::debug("[p2p_node] run_seeding: before seeds check"); if (settings_.seeds.empty()) { spdlog::info("[p2p_node] No seeds configured"); co_return; } - spdlog::debug("[p2p_node] run_seeding: getting executor"); - auto executor = co_await ::asio::this_coro::executor; - spdlog::debug("[p2p_node] run_seeding: got executor"); - - // Track seeds completed - auto seeds_completed = std::make_shared>(0); - auto const total_seeds = settings_.seeds.size(); - spdlog::debug("[p2p_node] run_seeding: total_seeds = {}", total_seeds); + // Use pool's executor for parallel DNS resolution, not this_coro::executor + // (which might be a single-threaded io_context from the caller) + auto executor = pool_.get_executor(); // Copy seeds to avoid reference issues in coroutines - spdlog::debug("[p2p_node] run_seeding: copying seeds"); std::vector seeds_copy( settings_.seeds.begin(), settings_.seeds.end()); - spdlog::debug("[p2p_node] run_seeding: seeds copied, count = {}", seeds_copy.size()); - // Launch seed connections in parallel - for (size_t i = 0; i < seeds_copy.size(); ++i) { - if (stopped_) break; + // Use task_group for structured concurrency - no detached! + task_group seed_tasks(executor); - auto const& seed = seeds_copy[i]; - spdlog::debug("[p2p_node] run_seeding: processing seed {} of {}", i + 1, seeds_copy.size()); + // Track seeds completed for early exit + auto seeds_completed = std::make_shared>(0); + auto const total_seeds = seeds_copy.size(); - auto seed_host = seed.host(); - auto seed_port = seed.port(); - spdlog::debug("[p2p_node] run_seeding: seed {}:{}", seed_host, seed_port); + // Launch all seed connections in parallel + for (auto const& seed : seeds_copy) { + if (stopped_) break; - // Use member function instead of lambda to avoid capture lifetime issues - spdlog::debug("[p2p_node] run_seeding: about to co_spawn connect_to_seed for {}:{}", seed_host, seed_port); - ::asio::co_spawn(executor, - connect_to_seed(std::move(seed_host), seed_port, seeds_completed), - ::asio::detached); - spdlog::debug("[p2p_node] run_seeding: co_spawned connect_to_seed"); + seed_tasks.spawn([this, host = seed.host(), port = seed.port(), seeds_completed]() -> ::asio::awaitable { + co_await connect_to_seed(host, port, seeds_completed); + }); } - spdlog::debug("[p2p_node] run_seeding: all seed tasks spawned, entering wait loop"); + spdlog::debug("[p2p_node] run_seeding: {} seed tasks spawned", seeds_copy.size()); - // Wait for seeds with simple timeout + // Wait for seeds with early exit conditions + // We use a timer loop to check for early exit while tasks run + ::asio::steady_timer check_timer(executor); auto const max_wait = std::chrono::seconds(settings_.connect_timeout_seconds + 35); auto const start_time = std::chrono::steady_clock::now(); - while (*seeds_completed < total_seeds && !stopped_) { + while (seed_tasks.has_active_tasks() && !stopped_) { // Check elapsed time - auto elapsed = std::chrono::steady_clock::now() - start_time; - if (elapsed >= max_wait) { + if (std::chrono::steady_clock::now() - start_time >= max_wait) { spdlog::debug("[p2p_node] Seeding timeout reached"); break; } @@ -398,11 +435,13 @@ ::asio::awaitable p2p_node::run_seeding() { } // Wait a bit before checking again - ::asio::steady_timer check_timer(executor); check_timer.expires_after(1s); co_await check_timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); } + // Wait for remaining tasks to complete (structured concurrency) + co_await seed_tasks.join(); + spdlog::info("[p2p_node] Seeding complete, {} addresses available", hosts_.count()); } @@ -413,7 +452,8 @@ ::asio::awaitable p2p_node::connect_to_seed( { spdlog::debug("[p2p_node] connect_to_seed: starting for {}:{}", seed_host, seed_port); - auto executor = co_await ::asio::this_coro::executor; + // Use pool's executor explicitly for parallel operations + auto executor = pool_.get_executor(); try { auto result = co_await async_connect( @@ -433,75 +473,77 @@ ::asio::awaitable p2p_node::connect_to_seed( spdlog::debug("[p2p_node] connect_to_seed: connected to {}:{}", seed_host, seed_port); auto peer = *result; - // Start the session's message pump - spdlog::debug("[p2p_node] connect_to_seed: spawning peer->run() for {}:{}", seed_host, seed_port); - ::asio::co_spawn(executor, peer->run(), ::asio::detached); - - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - - // Perform handshake - spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { - peer->stop(); - spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", - seed_host, seed_port, handshake_result.error().message()); - ++(*seeds_completed); - co_return; - } + // Run the seeding protocol using structured concurrency: + // peer->run() && seeding_protocol() + // This eliminates the need for detached coroutines! + co_await ( + peer->run() && + [&]() -> ::asio::awaitable { + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + + // Perform handshake (uses channels - run() is running in parallel!) + spdlog::debug("[p2p_node] connect_to_seed: performing handshake for {}:{}", seed_host, seed_port); + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + spdlog::debug("[p2p_node] Seed handshake failed {}:{} - {}", + seed_host, seed_port, handshake_result.error().message()); + peer->stop(); + co_return; + } - spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); + spdlog::debug("[p2p_node] connect_to_seed: handshake complete for {}:{}", seed_host, seed_port); - // Send getaddr request - auto ec = co_await peer->send(domain::message::get_address{}); - if (ec != error::success) { - peer->stop(); - ++(*seeds_completed); - co_return; - } + // Send getaddr request + auto ec = co_await peer->send(domain::message::get_address{}); + if (ec != error::success) { + peer->stop(); + co_return; + } - // Wait for addr response with timeout - ::asio::steady_timer timer(executor); - timer.expires_after(30s); - bool got_addresses = false; + // Wait for addr response with timeout + ::asio::steady_timer timer(executor); + timer.expires_after(30s); + bool got_addresses = false; - while (!got_addresses && !peer->stopped()) { - auto msg_result = co_await ( - peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || - timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) - ); + while (!got_addresses && !peer->stopped()) { + auto msg_result = co_await ( + peer->messages().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); - if (msg_result.index() == 1) { - // Timeout - break; - } + if (msg_result.index() == 1) { + // Timeout + break; + } - auto& [recv_ec, raw] = std::get<0>(msg_result); - if (recv_ec) { - break; - } + auto& [recv_ec, raw] = std::get<0>(msg_result); + if (recv_ec) { + break; + } - if (raw.heading.command() == domain::message::address::command) { - byte_reader reader(raw.payload); - auto addr_result = domain::message::address::from_data( - reader, peer->negotiated_version()); - if (addr_result) { - auto const count = addr_result->addresses().size(); - spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", - count, seed_host, seed_port); - - for (auto const& addr : addr_result->addresses()) { - hosts_.store(addr); + if (raw.heading.command() == domain::message::address::command) { + byte_reader reader(raw.payload); + auto addr_result = domain::message::address::from_data( + reader, peer->negotiated_version()); + if (addr_result) { + auto const count = addr_result->addresses().size(); + spdlog::info("[p2p_node] Got {} addresses from seed {}:{}", + count, seed_host, seed_port); + + for (auto const& addr : addr_result->addresses()) { + hosts_.store(addr); + } + got_addresses = true; + } } - got_addresses = true; } - } - } - peer->stop(); + peer->stop(); + }() + ); } catch (std::exception const& e) { spdlog::debug("[p2p_node] Seed {} exception: {}", seed_host, e.what()); } @@ -530,6 +572,11 @@ ::asio::awaitable p2p_node::run_inbound() { acceptor_ = std::make_unique<::asio::ip::tcp::acceptor>(std::move(*listen_result)); + // Wait for peer_supervisor to be ready (deterministic synchronization) + while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { + co_await ::asio::post(executor, ::asio::use_awaitable); + } + spdlog::info("[p2p_node] Listening on port {}", settings_.inbound_port); // Accept loop @@ -547,58 +594,25 @@ ::asio::awaitable p2p_node::run_inbound() { auto peer = *result; - // Handle the new connection in a separate coroutine - ::asio::co_spawn(executor, [this, peer, executor]() -> ::asio::awaitable { - // Check banlist before proceeding - if (banlist_.is_banned(peer->authority())) { - spdlog::debug("[p2p_node] Rejecting inbound connection from banned peer {}", - peer->authority()); - peer->stop(); - co_return; - } - - // Start the session's message pump - ::asio::co_spawn(executor, peer->run(), ::asio::detached); - - // Generate nonce for handshake - uint64_t nonce = generate_nonce(); - - // Perform handshake - auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); - auto handshake_result = co_await perform_handshake(*peer, config); - - if (!handshake_result) { - peer->stop(); - spdlog::debug("[p2p_node] Inbound handshake failed: {}", - handshake_result.error().message()); - co_return; - } - - spdlog::info("[p2p_node] Inbound handshake complete from {}, version {}, {}", - peer->authority(), handshake_result->negotiated_version, - handshake_result->peer_version->user_agent()); - - // Send initial ping immediately to get latency data quickly (like BCHN) - { - uint64_t nonce = 0; - pseudo_random::fill(reinterpret_cast(&nonce), sizeof(nonce)); - domain::message::ping ping_msg(nonce); - auto ec = co_await peer->send(ping_msg); - if (ec == error::success) { - peer->record_ping_sent(nonce); - } - } - - // Add to peer manager - auto ec = co_await manager_.add(peer); - if (ec != error::success) { - peer->stop(); - co_return; - } + // Check banlist before proceeding + if (banlist_.is_banned(peer->authority())) { + spdlog::debug("[p2p_node] Rejecting inbound connection from banned peer {}", + peer->authority()); + peer->stop(); + continue; + } - // Start protocol handlers - co_await run_peer_protocols(peer); - }, ::asio::detached); + // Send peer to supervisor for FULL lifecycle management (structured concurrency) + // Supervisor will do: peer->run() && (handshake && add_to_manager && protocols) + // No response channel needed for inbound - we don't wait for handshake result + if (new_peer_channel_ && new_peer_channel_->is_open()) { + co_await new_peer_channel_->async_send( + std::error_code{}, + peer_event{peer, peer_direction::inbound, nullptr}, + ::asio::use_awaitable); + } else { + peer->stop(); + } } } @@ -694,6 +708,15 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { auto executor = co_await ::asio::this_coro::executor; ::asio::steady_timer timer(executor); + // Wait for peer_supervisor to be ready (deterministic synchronization) + // The && operator starts coroutines but doesn't guarantee execution order. + while (!supervisor_ready_.load(std::memory_order_acquire) && !stopped_) { + // Yield to allow peer_supervisor to start + co_await ::asio::post(executor, ::asio::use_awaitable); + } + + spdlog::debug("[p2p_node] maintain_outbound_connections started"); + // Maximum number of parallel connection attempts constexpr size_t max_parallel_attempts = 8; @@ -758,8 +781,8 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { spdlog::debug("[p2p_node] Attempting {} parallel connections (need {}, have {})", addresses.size(), needed, current_count); - // Track successful connections with a shared atomic counter - auto success_count = std::make_shared>(0); + // Use task_group for structured concurrency - no detached! + task_group connection_tasks(executor); for (auto const& addr : addresses) { auto const authority = infrastructure::config::authority(addr); @@ -768,7 +791,7 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { // Add to pending connections before spawning pending_connections_.insert(ip); - auto task = [this, addr, ip, success_count]() -> ::asio::awaitable { + connection_tasks.spawn([this, addr, ip]() -> ::asio::awaitable { auto const authority = infrastructure::config::authority(addr); spdlog::trace("[p2p_node] Attempting connection to {}", authority); @@ -783,28 +806,175 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { hosts_.remove(addr); } else { spdlog::debug("[p2p_node] Connected to {}", authority); - ++(*success_count); } - }; - - // Spawn each connection attempt - ::asio::co_spawn(executor, task(), ::asio::detached); + }); } - // Give connection attempts time to complete - // Use a shorter wait since they're running in parallel - timer.expires_after(std::chrono::seconds(settings_.connect_timeout_seconds + 2)); - co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + // Wait for ALL connection attempts to complete (structured concurrency!) + co_await connection_tasks.join(); // Continue loop to check if we need more connections continue; } } - // Wait before next check when we have enough connections - timer.expires_after(std::chrono::seconds(30)); + // Wait before next check (short interval so shutdown is responsive) + // NOTE: We don't use || with stop_signal_ because the || operator in asio + // waits for BOTH operations to complete, not just the first one. + timer.expires_after(std::chrono::seconds(5)); co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + // Loop will exit on next iteration if stopped_ is true + } +} + +// ============================================================================= +// Peer Supervisor (Structured Concurrency) +// ============================================================================= +// +// The peer_supervisor manages all peer lifecycles using the nursery pattern. +// Instead of spawning detached coroutines for each peer, all peer tasks are +// tracked in a task_group and properly awaited on shutdown. +// +// Flow: +// 1. run_inbound() and connect() send peer_events to new_peer_channel_ +// 2. peer_supervisor receives events and spawns peer tasks into task_group +// 3. On stop(), stop_signal_ is triggered +// 4. peer_supervisor stops accepting new peers and waits for all tasks to complete +// +// ============================================================================= + +::asio::awaitable p2p_node::peer_supervisor() { + spdlog::debug("[p2p_node] peer_supervisor started"); + + task_group peer_tasks(pool_.get_executor()); + + // Track ALL spawned peers (including those not yet in manager) + // This is needed for clean shutdown - manager_.stop_all() only stops + // peers that completed handshake, but we need to stop ALL peers. + std::vector all_spawned_peers; + + // Signal that we're ready to receive peers (deterministic synchronization) + supervisor_ready_.store(true, std::memory_order_release); + + while (!stopped_) { + // Wait for new peer event + // NOTE: We don't use || with stop_signal_ because the || operator in asio + // waits for BOTH operations to complete, not just the first one. + // Instead, stop() closes new_peer_channel_ which causes async_receive to return error. + auto [ec, event] = co_await new_peer_channel_->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + // Channel closed (stop() was called) or error - exit + spdlog::debug("[p2p_node] peer_supervisor channel closed: {}", ec.message()); + break; + } + + auto peer = event.peer; + auto direction = event.direction; + auto response_channel = event.response_channel; + + // Track this peer for shutdown + all_spawned_peers.push_back(peer); + + spdlog::debug("[p2p_node] peer_supervisor received {} peer [{}]", + direction == peer_direction::inbound ? "inbound" : "outbound", + peer->authority()); + + // Spawn FULL peer lifecycle into the task group (tracked, not detached!) + // This runs: peer->run() && (handshake && add_to_manager && protocols) + // The && operator ensures both branches run in parallel and we wait for both. + // When peer disconnects, both exit and && completes. + peer_tasks.spawn([this, peer, direction, response_channel]() -> ::asio::awaitable { + try { + co_await ( + peer->run() && + [&]() -> ::asio::awaitable { + // Generate nonce for handshake + uint64_t nonce = generate_nonce(); + auto config = make_handshake_config(settings_, top_block_.load().height(), nonce); + + // Perform handshake (uses channels - run() is already running!) + auto handshake_result = co_await perform_handshake(*peer, config); + + if (!handshake_result) { + spdlog::debug("[p2p_node] Handshake failed for [{}]: {}", + peer->authority(), handshake_result.error().message()); + // Send failure response if caller is waiting + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{handshake_result.error()}); + } + peer->stop(); + co_return; + } + + spdlog::info("[p2p_node] Handshake complete with [{}], version {}, {}", + peer->authority(), handshake_result->negotiated_version, + handshake_result->peer_version->user_agent()); + + // Add to peer manager + auto add_ec = co_await manager_.add(peer); + if (add_ec != error::success) { + spdlog::debug("[p2p_node] Failed to add peer [{}] to manager: {}", + peer->authority(), add_ec.message()); + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{add_ec}); + } + peer->stop(); + co_return; + } + + // Send initial ping to get latency data + { + uint64_t ping_nonce = 0; + pseudo_random::fill(reinterpret_cast(&ping_nonce), sizeof(ping_nonce)); + domain::message::ping ping_msg(ping_nonce); + auto ec = co_await peer->send(ping_msg); + if (ec == error::success) { + peer->record_ping_sent(ping_nonce); + } + } + + // Send success response to caller + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{error::success}); + } + + // Run protocols until peer disconnects + co_await run_peer_protocols(peer); + }() + ); + } catch (std::exception const& e) { + spdlog::debug("[p2p_node] Peer [{}] task exception: {}", + peer->authority(), e.what()); + // Send error response if caller is still waiting + if (response_channel) { + response_channel->try_send(std::error_code{}, handshake_response{error::operation_failed}); + } + } + + spdlog::debug("[p2p_node] Peer [{}] full lifecycle completed", peer->authority()); + }); } + + spdlog::debug("[p2p_node] peer_supervisor stopping {} spawned peers before join", + all_spawned_peers.size()); + + // Stop ALL spawned peers (including those not yet in manager) + // This ensures peers still in handshake phase are also stopped, + // allowing their run() to exit and peer_tasks.join() to complete. + for (auto& peer : all_spawned_peers) { + peer->stop(); + } + + spdlog::debug("[p2p_node] peer_supervisor waiting for {} active peer tasks", + peer_tasks.active_count()); + + // CRITICAL: Wait for all peer tasks to complete + // This is the structured concurrency guarantee - no orphaned tasks! + co_await peer_tasks.join(); + + spdlog::debug("[p2p_node] peer_supervisor finished - all peer tasks completed"); } uint64_t p2p_node::generate_nonce() { diff --git a/src/network/src/peer_manager.cpp b/src/network/src/peer_manager.cpp index 44b23dab..86f79a17 100644 --- a/src/network/src/peer_manager.cpp +++ b/src/network/src/peer_manager.cpp @@ -88,7 +88,7 @@ ::asio::awaitable peer_manager::add(peer_session::ptr peer) { } ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { - if (!peer || stopped()) { + if (!peer) { co_return; } @@ -102,10 +102,10 @@ ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { } ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { - // Skip if already stopped - the destructor will handle cleanup - if (stopped()) { - co_return; - } + // Note: With structured concurrency, remove() is called from peer tasks + // that are tracked by task_group. The peer_supervisor waits for all tasks + // to complete before shutdown finishes, so this operation is safe. + // We don't check stopped() because we want cleanup to proceed normally. co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { auto it = peers_.find(nonce); @@ -222,8 +222,9 @@ void peer_manager::stop_all() { spdlog::debug("[peer_manager] Stopping all peers"); - // Post to strand to safely iterate and clean up - // Note: Callers should run the io_context to ensure completion + // Post to strand to safely stop all peers and clear the map. + // Note: With structured concurrency, peer tasks may still call remove() after + // this, but remove() handles "not found" gracefully (just does nothing). ::asio::post(strand_, [this]() { for (auto& [nonce, peer] : peers_) { peer->stop(); diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp index f78cfb24..44439cb8 100644 --- a/src/network/src/peer_session.cpp +++ b/src/network/src/peer_session.cpp @@ -151,6 +151,8 @@ void peer_session::stop(code const& ec) { // Close channels outbound_.close(); inbound_.close(); + headers_responses_.close(); + block_responses_.close(); // Shutdown socket boost_code ignore; @@ -537,6 +539,15 @@ awaitable_expected peer_session::read_message() { co_return raw_message{head, std::move(payload)}; } +// ============================================================================= +// Direct I/O (for handshake before run() starts) +// ============================================================================= + +awaitable_expected peer_session::read_message_direct() { + // Just delegate to the private read_message() implementation + return read_message(); +} + void peer_session::signal_activity() { activity_signaled_ = true; // Cancel and restart the inactivity timer @@ -557,14 +568,68 @@ awaitable_expected async_connect( using namespace ::asio::experimental::awaitable_operators; // Create resolver - ::asio::ip::tcp::resolver resolver(executor); + auto resolver = std::make_shared<::asio::ip::tcp::resolver>(executor); + + // DNS resolution timeout (5 seconds should be plenty for DNS) + auto dns_timer = std::make_shared<::asio::steady_timer>(executor); + dns_timer->expires_after(std::chrono::seconds(5)); + + auto start_time = std::chrono::steady_clock::now(); + spdlog::debug("[async_connect] Starting DNS resolution for {} with 5s timeout", hostname); + + // Use a channel to get the first result (DNS or timeout) + auto result_channel = std::make_shared, + std::error_code + > + >>(executor, 1); + + // Spawn DNS resolution + ::asio::co_spawn(executor, [resolver, hostname, port, result_channel]() -> ::asio::awaitable { + auto [ec, endpoints] = co_await resolver->async_resolve( + hostname, std::to_string(port), ::asio::as_tuple(::asio::use_awaitable)); + result_channel->try_send(std::error_code{}, + std::variant, std::error_code>{ + std::make_tuple(ec, endpoints)}); + }, ::asio::detached); + + // Spawn timer + ::asio::co_spawn(executor, [dns_timer, result_channel]() -> ::asio::awaitable { + auto [ec] = co_await dns_timer->async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + result_channel->try_send(std::error_code{}, + std::variant, std::error_code>{ + std::make_error_code(std::errc::timed_out)}); + } + }, ::asio::detached); - // Resolve hostname - auto [resolve_ec, endpoints] = co_await resolver.async_resolve( - hostname, - std::to_string(port), + // Wait for first result + auto [recv_ec, result] = co_await result_channel->async_receive( ::asio::as_tuple(::asio::use_awaitable)); + auto elapsed = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start_time).count(); + + // Cancel whichever didn't complete + resolver->cancel(); + dns_timer->cancel(); + + if (recv_ec) { + spdlog::debug("[async_connect] DNS channel error for {}: {}", hostname, recv_ec.message()); + co_return std::unexpected(error::resolve_failed); + } + + // Check which result we got + if (result.index() == 1) { + // Timeout + spdlog::debug("[async_connect] DNS resolution for {} timed out after {}ms", hostname, elapsed); + co_return std::unexpected(error::resolve_failed); + } + + auto [resolve_ec, endpoints] = std::get<0>(result); + spdlog::debug("[async_connect] DNS completed for {} in {}ms, ec={}", hostname, elapsed, resolve_ec.message()); + if (resolve_ec) { spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); co_return std::unexpected(error::resolve_failed); @@ -576,18 +641,18 @@ awaitable_expected async_connect( timer.expires_after(timeout); // Race: connect vs timeout - auto result = co_await ( + auto connect_result = co_await ( ::asio::async_connect(socket, endpoints, ::asio::as_tuple(::asio::use_awaitable)) || timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) ); - if (result.index() == 1) { + if (connect_result.index() == 1) { // Timeout won spdlog::debug("[async_connect] Connection to {}:{} timed out", hostname, port); co_return std::unexpected(error::channel_timeout); } - auto [connect_ec, endpoint] = std::get<0>(result); + auto [connect_ec, endpoint] = std::get<0>(connect_result); if (connect_ec) { spdlog::debug("[async_connect] Failed to connect to {}:{}: {}", hostname, port, connect_ec.message()); diff --git a/src/network/src/protocols_coro.cpp b/src/network/src/protocols_coro.cpp index 1cd5d7b7..fed1555b 100644 --- a/src/network/src/protocols_coro.cpp +++ b/src/network/src/protocols_coro.cpp @@ -219,6 +219,132 @@ awaitable_expected perform_handshake( co_return handshake_result{peer_version, negotiated}; } +// ============================================================================= +// Direct Handshake (no message pump required) +// ============================================================================= +// +// This version of handshake reads/writes directly to the socket without +// needing peer->run() to be running. This enables structured concurrency +// by eliminating the need to spawn run() with detached before handshake. +// +// After handshake completes, the peer is sent to peer_supervisor which +// spawns run() + protocols in a tracked task_group. +// +// ============================================================================= + +awaitable_expected perform_handshake_direct( + peer_session& peer, + handshake_config const& config) +{ + auto const& authority = peer.authority(); + + spdlog::debug("[protocol] Starting direct handshake with [{}]", authority); + + // Send our version message (directly to socket) + auto version_msg = make_version_message(config, authority); + auto send_ec = co_await peer.send_direct(version_msg); + if (send_ec != error::success) { + spdlog::debug("[protocol] Failed to send version to [{}]", authority); + co_return std::unexpected(send_ec); + } + + // We need to receive both version and verack from the peer + // The order may vary, so we track what we've received + bool got_version = false; + bool got_verack = false; + domain::message::version::const_ptr peer_version; + + auto deadline = std::chrono::steady_clock::now() + config.timeout; + auto executor = co_await ::asio::this_coro::executor; + + while (!got_version || !got_verack) { + auto remaining = std::chrono::duration_cast( + deadline - std::chrono::steady_clock::now()); + + if (remaining <= 0s) { + spdlog::debug("[protocol] Handshake timeout with [{}]", authority); + co_return std::unexpected(error::channel_timeout); + } + + // Read message directly from socket with timeout + // Use racing pattern with timer + ::asio::steady_timer timer(executor, remaining); + + auto result = co_await ( + peer.read_message_direct() || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + // Check which completed first + if (result.index() == 1) { + // Timer won - timeout + spdlog::debug("[protocol] Handshake timeout with [{}]", authority); + co_return std::unexpected(error::channel_timeout); + } + + // Message received + auto& msg_result = std::get<0>(result); + if (!msg_result) { + spdlog::debug("[protocol] Failed to receive message from [{}]: {}", + authority, msg_result.error().message()); + co_return std::unexpected(msg_result.error()); + } + + auto const& raw = *msg_result; + auto const& command = raw.heading.command(); + + if (command == domain::message::version::command && !got_version) { + // Parse version message + byte_reader reader(raw.payload); + auto version_result = domain::message::version::from_data(reader, peer.negotiated_version()); + if (!version_result) { + spdlog::debug("[protocol] Failed to parse version from [{}]", authority); + co_return std::unexpected(error::bad_stream); + } + auto version = std::make_shared(std::move(*version_result)); + + spdlog::debug("[protocol] Received version from [{}] protocol ({}) user agent: {}", + authority, version->value(), version->user_agent()); + + // Validate + if (!validate_peer_version(*version, config, authority)) { + co_return std::unexpected(error::channel_stopped); + } + + peer_version = version; + got_version = true; + + // Send verack in response (directly to socket) + auto verack_ec = co_await peer.send_direct(domain::message::verack{}); + if (verack_ec != error::success) { + spdlog::debug("[protocol] Failed to send verack to [{}]", authority); + co_return std::unexpected(verack_ec); + } + } + else if (command == domain::message::verack::command && !got_verack) { + spdlog::debug("[protocol] Received verack from [{}]", authority); + got_verack = true; + } + else { + // Unexpected message during handshake - log but continue + spdlog::debug("[protocol] Unexpected message '{}' during handshake with [{}]", + command, authority); + } + } + + // Calculate negotiated version + auto negotiated = std::min(peer_version->value(), config.protocol_version); + + // Update peer session + peer.set_peer_version(peer_version); + peer.set_negotiated_version(negotiated); + + spdlog::debug("[protocol] Direct handshake complete with [{}], negotiated version {}", + authority, negotiated); + + co_return handshake_result{peer_version, negotiated}; +} + handshake_config make_handshake_config( settings const& network_settings, uint32_t current_height, diff --git a/src/network/src/settings.cpp b/src/network/src/settings.cpp index 6158b2f7..9864f078 100644 --- a/src/network/src/settings.cpp +++ b/src/network/src/settings.cpp @@ -86,8 +86,8 @@ settings::settings(domain::config::network context) seeds.emplace_back("bchseed.c3-soft.com", 8333); // C3 Soft (NilacTheGrim) seeds.emplace_back("bch.bitjson.com", 8333); // Jason Dreyzehner - // TODO(fernando): TEMPORARY - hardcoded peer for testing - peers.emplace_back("194.14.247.36", 8333); + // // TODO(fernando): TEMPORARY - hardcoded peer for testing + // peers.emplace_back("194.14.247.36", 8333); #else identifier = netmagic::btc_mainnet; seeds.reserve(6); diff --git a/src/node-exe/src/main.cpp b/src/node-exe/src/main.cpp index 274316d5..949f99a8 100644 --- a/src/node-exe/src/main.cpp +++ b/src/node-exe/src/main.cpp @@ -2,7 +2,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include +#include #include #include #include @@ -15,6 +17,8 @@ #include #include +#include + #include "tui_dashboard.hpp" KTH_USE_MAIN @@ -39,20 +43,57 @@ void do_settings(kth::node::parser& metadata, std::ostream& output) { print.settings(output); } +// Global signal state for run_with_log +namespace { + std::atomic g_signal_received{0}; + + extern "C" void log_mode_signal_handler(int signal_number) { + std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); + std::fflush(stderr); + g_signal_received.store(signal_number); + } +} + bool run_with_log(kth::node::executor& host) { // Traditional log mode - scrolling output + // Install signal handler IMMEDIATELY so Ctrl-C works during startup + g_signal_received.store(0); + auto prev_sigint = std::signal(SIGINT, log_mode_signal_handler); + auto prev_sigterm = std::signal(SIGTERM, log_mode_signal_handler); + // Start node (blocks until ready) auto ec = host.start(); if (ec != kth::error::success) { + // Restore handlers + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); return false; } - // Wait for SIGINT/SIGTERM - host.wait_for_stop_signal(); + // Check if signal was received during startup + if (g_signal_received.load() != 0) { + spdlog::info("[node] Signal received during startup, stopping..."); + host.stop(); + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + return true; + } + + // Wait for SIGINT/SIGTERM (poll the atomic) + while (g_signal_received.load() == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + spdlog::info("[node] Stop signal detected (code: {}).", g_signal_received.load()); // Stop node (blocks until stopped) host.stop(); + + // Restore handlers + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + return true; } diff --git a/src/node/include/kth/node/full_node.hpp b/src/node/include/kth/node/full_node.hpp index 6d15d4c7..3ef94c2f 100644 --- a/src/node/include/kth/node/full_node.hpp +++ b/src/node/include/kth/node/full_node.hpp @@ -213,6 +213,12 @@ class KND_API full_node : public multi_crypto_setter { block_const_ptr_list_const_ptr incoming, block_const_ptr_list_const_ptr outgoing); + // Background task coroutines (for structured concurrency) + ::asio::awaitable run_blockchain_subscriber(); +#if ! defined(__EMSCRIPTEN__) + ::asio::awaitable run_sync(); +#endif + // Configuration references (stored in configuration object) node::settings const& node_settings_; blockchain::settings const& chain_settings_; diff --git a/src/node/src/executor/executor.cpp b/src/node/src/executor/executor.cpp index 40ca7d32..cc892b42 100644 --- a/src/node/src/executor/executor.cpp +++ b/src/node/src/executor/executor.cpp @@ -143,24 +143,19 @@ void executor::start_async(start_handler handler) { if (handler) { handler(start_ec); } - co_return; - } - - spdlog::info("[node] Seeding is complete."); - - // Run the node (starts P2P, sync, etc.) - auto run_ec = co_await node_->run(); - if (run_ec != error::success) { - spdlog::error("[node] Node failed to start with error: {}.", run_ec.message()); - if (handler) { - handler(run_ec); + // Notify sync version + { + std::lock_guard lock(start_mutex_); + start_result_ = start_ec; } + start_cv_.notify_all(); co_return; } - spdlog::info("[node] Node is started."); + spdlog::info("[node] Seeding is complete."); - // Mark as running + // Mark as running BEFORE calling run() so start() can return + // run() blocks until the node is stopped, so we must notify first state_ = state::running; // Notify handler @@ -168,13 +163,24 @@ void executor::start_async(start_handler handler) { handler(error::success); } - // Also notify sync version if waiting + // Notify sync version so start() can return { std::lock_guard lock(start_mutex_); start_result_ = error::success; } start_cv_.notify_all(); + spdlog::info("[node] Node is started."); + + // Run the node (starts P2P, sync, etc.) + // This blocks until the node is stopped (via stop()) + auto run_ec = co_await node_->run(); + if (run_ec != error::success && run_ec != error::service_stopped) { + spdlog::error("[node] Node run ended with error: {}.", run_ec.message()); + } + + spdlog::debug("[node] Node run() completed."); + }, [this, handler](std::exception_ptr ep) { if (ep) { try { @@ -242,10 +248,14 @@ code executor::start() { // Start async start_async(nullptr); - // Wait for completion - start_cv_.wait(lock, [this]() { + // Wait for completion with periodic wakeup + // This allows external signal handlers to interrupt us + while (!start_cv_.wait_for(lock, std::chrono::milliseconds(100), [this]() { return state_.load() == state::running || start_result_ != error::success; - }); + })) { + // Check if we should abort (e.g., signal received) + // The caller can check g_signal_received after start() returns + } return start_result_; } @@ -273,35 +283,40 @@ void executor::stop() { stop_io_thread(); } -void executor::wait_for_stop_signal() { - std::promise signal_promise; - auto signal_future = signal_promise.get_future(); +// Global variable for signal handling (required for std::signal) +namespace { + std::atomic g_signal_received{0}; + std::atomic g_signal_waiting{false}; + + void signal_handler(int signal_number) { + // Immediate print to stderr (unbuffered) so user sees it right away + // Note: fprintf is async-signal-safe, std::println is not + std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); + std::fflush(stderr); + g_signal_received.store(signal_number); + } +} - // Use a separate io_context for signal handling - ::asio::io_context signal_context; - auto work_guard = ::asio::make_work_guard(signal_context); - ::asio::signal_set signals(signal_context, SIGINT, SIGTERM); +void executor::wait_for_stop_signal() { + // Mark that we're waiting for a signal + g_signal_waiting.store(true); - signals.async_wait([&signal_promise, &work_guard](std::error_code const& ec, int signal_number) { - if (!ec) { - signal_promise.set_value(signal_number); - } - work_guard.reset(); // Allow io_context to stop - }); + // Install signal handlers using std::signal (simpler and more reliable) + auto prev_sigint = std::signal(SIGINT, signal_handler); + auto prev_sigterm = std::signal(SIGTERM, signal_handler); - // Run io_context in background thread - std::thread signal_thread([&signal_context]() { - signal_context.run(); - }); + // Poll for signal (simple and reliable) + while (g_signal_received.load() == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } - // Wait for signal - auto signal_received = signal_future.get(); + auto signal_received = g_signal_received.load(); spdlog::info("[node] Stop signal detected (code: {}).", signal_received); - // Cleanup - if (signal_thread.joinable()) { - signal_thread.join(); - } + // Restore previous handlers + std::signal(SIGINT, prev_sigint); + std::signal(SIGTERM, prev_sigterm); + g_signal_waiting.store(false); } // ============================================================================= diff --git a/src/node/src/full_node.cpp b/src/node/src/full_node.cpp index 26f26699..7460890e 100644 --- a/src/node/src/full_node.cpp +++ b/src/node/src/full_node.cpp @@ -19,12 +19,14 @@ #include #include #include +#include namespace kth::node { using namespace kth::blockchain; using namespace kth::domain::chain; using namespace kth::domain::config; +using namespace ::asio::experimental::awaitable_operators; #if ! defined(__EMSCRIPTEN__) using namespace kth::network; @@ -65,6 +67,9 @@ full_node::full_node(configuration const& configuration) #endif { #if ! defined(__EMSCRIPTEN__) + spdlog::debug("[full_node] configuration.network.threads = {}", configuration.network.threads); + spdlog::debug("[full_node] network_settings_.threads = {}", network_settings_.threads); + // Set user agent after initialization (network_ holds reference to network_settings_) std::vector features; #if defined(KTH_CURRENCY_BCH) @@ -140,81 +145,94 @@ ::asio::awaitable full_node::run() { spdlog::info("[node] Node start heights: header-sync ({}), block-sync ({}).", header_height, block_height); - // Subscribe to blockchain reorganizations +#if ! defined(__EMSCRIPTEN__) + // Run all background tasks in parallel using structured concurrency. + // This blocks until ALL tasks complete (i.e., until stop() is called). + // No detached coroutines - everything is properly awaited. + spdlog::debug("[full_node] Starting parallel tasks with && operator"); + co_await ( + run_blockchain_subscriber() && + network_.run() && + run_sync() + ); + spdlog::debug("[full_node] All parallel tasks completed"); +#else + // WASM: only blockchain subscriber (no network) + co_await run_blockchain_subscriber(); +#endif + + co_return error::success; +} + +::asio::awaitable full_node::run_blockchain_subscriber() { + spdlog::debug("[full_node] run_blockchain_subscriber() starting"); auto blockchain_channel = subscribe_blockchain(); - if (blockchain_channel) { - ::asio::co_spawn(chain_.executor(), [this, blockchain_channel]() -> ::asio::awaitable { - while (blockchain_channel->is_open() && !stopped()) { - auto result = co_await blockchain_channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); - auto& [ec, fork_height, incoming, outgoing] = result; - - if (ec) { - break; - } - - if ( ! handle_reorganized(error::success, fork_height, incoming, outgoing)) { - unsubscribe_blockchain(blockchain_channel); - break; - } - } - }, ::asio::detached); + if (!blockchain_channel) { + spdlog::debug("[full_node] run_blockchain_subscriber() - no channel, exiting"); + co_return; } + spdlog::debug("[full_node] run_blockchain_subscriber() - channel obtained, entering loop"); -#if ! defined(__EMSCRIPTEN__) - // Run the P2P network (starts connections and protocol handlers) - auto ec = co_await network_.run(); - if (ec != error::success) { - spdlog::error("[node] Failure running network: {}", ec.message()); - co_return ec; + while (blockchain_channel->is_open() && !stopped()) { + auto result = co_await blockchain_channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); + auto& [ec, fork_height, incoming, outgoing] = result; + + if (ec) { + break; + } + + if (!handle_reorganized(error::success, fork_height, incoming, outgoing)) { + unsubscribe_blockchain(blockchain_channel); + break; + } } +} - // Start sync in background - // TODO(fernando): Make this configurable and add proper sync management - // TODO(fernando): blockchain::block_chain should migrate to coroutines - // (organize, fetch_*, etc.) to eliminate callbacks and std::promise usage - ::asio::co_spawn(network_.thread_pool().get_executor(), - [this]() -> ::asio::awaitable { - auto executor = co_await ::asio::this_coro::executor; - ::asio::steady_timer timer(executor); - - constexpr auto retry_delay = std::chrono::seconds(10); - - while (!stopped()) { - // Wait until we have at least one connected peer - while (!stopped() && network_.connection_count() == 0) { - timer.expires_after(std::chrono::milliseconds(500)); - co_await timer.async_wait(::asio::use_awaitable); - } - - if (stopped()) { - co_return; - } - - spdlog::info("[node] Starting initial block sync..."); - auto result = co_await sync_from_best_peer(chain_, network_, network_type_); - - if (result.error) { - spdlog::warn("[node] Sync failed: {}, retrying in {}s...", - result.error.message(), retry_delay.count()); - - // Wait before retrying - timer.expires_after(retry_delay); - auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - co_return; // Timer cancelled, node stopping - } - continue; - } - - spdlog::info("[node] Initial sync complete: {} headers, {} blocks, height {}", - result.headers_received, result.blocks_received, result.final_height); - break; // Sync successful, exit loop +#if ! defined(__EMSCRIPTEN__) +::asio::awaitable full_node::run_sync() { + spdlog::debug("[full_node] run_sync() starting"); + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + constexpr auto retry_delay = std::chrono::seconds(10); + + while (!stopped()) { + // Wait until we have at least one connected peer + spdlog::debug("[full_node] run_sync() waiting for peers, count={}", network_.connection_count()); + while (!stopped() && network_.connection_count() == 0) { + timer.expires_after(std::chrono::milliseconds(500)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return; } - }, ::asio::detached); -#endif + } - co_return error::success; + if (stopped()) { + co_return; + } + + spdlog::info("[node] Starting initial block sync..."); + auto result = co_await sync_from_best_peer(chain_, network_, network_type_); + + if (result.error) { + spdlog::warn("[node] Sync failed: {}, retrying in {}s...", + result.error.message(), retry_delay.count()); + + // Wait before retrying + timer.expires_after(retry_delay); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + co_return; // Timer cancelled, node stopping + } + continue; + } + + spdlog::info("[node] Initial sync complete: {} headers, {} blocks, height {}", + result.headers_received, result.blocks_received, result.final_height); + break; // Sync successful, exit loop + } } +#endif void full_node::stop() { #if ! defined(__EMSCRIPTEN__) From cc2bca5f0d7057a0fc96f97d3922ffe250529a55 Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Mon, 29 Dec 2025 22:45:14 +0100 Subject: [PATCH 14/14] feat(node): add parallel block download with lock-free coordinator v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement parallel block download system with two coordinator versions: V1 (strand-based): - Uses asio::strand for serialization instead of mutex - Avoids coroutine blocking issues from std::mutex V2 (lock-free): - Atomic CAS operations for chunk claiming - Slot-based system: 800 slots per round (8 peers × 100 multiplier) - 3 states: FREE (0), IN_PROGRESS (1), COMPLETED (2) - Peer watcher detects and adds new peers dynamically - Round advances when all slots complete Features: - Parallel downloads from multiple peers simultaneously - In-order block validation pipeline - Timeout detection for stalled downloads - Dynamic peer addition during sync - Progress logging with ETA, peer count, in-flight chunks Files added: - block_download_coordinator.hpp/cpp (V1) - block_download_coordinator_v2.hpp/cpp (V2) - parallel_sync.hpp/cpp (V1) - parallel_sync_v2.hpp/cpp (V2) --- banlist.dat | 1 + docs/design/STRUCTURED_CONCURRENCY_DESIGN.md | 383 +++++++++++ docs/parallel-block-download.md | 567 +++++++++++++++ hosts.cache | 645 ++++++++++++++++++ .../kth/blockchain/interface/block_chain.hpp | 4 +- .../kth/blockchain/pools/block_organizer.hpp | 3 +- .../kth/blockchain/pools/header_organizer.hpp | 9 +- .../include/kth/blockchain/settings.hpp | 2 + .../blockchain/validate/validate_block.hpp | 21 +- .../blockchain/validate/validate_header.hpp | 83 +++ src/blockchain/src/interface/block_chain.cpp | 105 ++- src/blockchain/src/pools/block_organizer.cpp | 8 +- src/blockchain/src/pools/header_organizer.cpp | 42 +- .../src/populate/populate_chain_state.cpp | 2 +- src/blockchain/src/settings.cpp | 6 + .../src/validate/validate_block.cpp | 128 +++- .../src/validate/validate_header.cpp | 316 ++++++++- .../test/block_index_bench/benchmarks.cpp | 2 +- src/consensus/src/bch-rules/coins.h | 2 +- .../src/bch-rules/script/interpreter.cpp | 2 +- .../src/bch-rules/util/strencodings.h | 2 +- .../src/btc-rules/script/interpreter.cpp | 2 +- .../database/databases/internal_database.ipp | 13 +- src/domain/include/kth/domain/chain/block.hpp | 7 +- .../include/kth/domain/chain/block_basis.hpp | 16 +- .../include/kth/domain/chain/header.hpp | 2 - .../include/kth/domain/chain/header_basis.hpp | 4 - .../include/kth/domain/config/parser.hpp | 7 +- .../include/kth/domain/constants/common.hpp | 9 +- .../kth/domain/impl/machine/interpreter.ipp | 2 +- src/domain/src/chain/block.cpp | 20 +- src/domain/src/chain/block_basis.cpp | 142 +--- src/domain/src/chain/chain_state.cpp | 2 +- src/domain/src/chain/header.cpp | 4 - src/domain/src/chain/header_basis.cpp | 25 - .../impl/utility/serializer.ipp | 4 +- .../infrastructure/utility/cpu_executor.hpp | 157 +++++ .../infrastructure/utility/pseudo_random.hpp | 2 +- .../kth/infrastructure/utility/task_group.hpp | 14 +- src/infrastructure/src/log/sink.cpp | 17 +- .../src/unicode/unicode_streambuf.cpp | 2 +- src/infrastructure/src/utility/png.cpp | 2 +- .../src/utility/system_memory.cpp | 18 +- .../include/kth/network/protocols_coro.hpp | 20 + src/network/include/kth/network/settings.hpp | 1 + src/network/src/banlist.cpp | 23 +- src/network/src/hosts.cpp | 4 +- src/network/src/p2p_node.cpp | 69 +- src/network/src/peer_manager.cpp | 11 + src/network/src/peer_session.cpp | 138 ++-- src/network/src/protocols_coro.cpp | 104 +++ src/network/src/settings.cpp | 1 + src/node-exe/src/main.cpp | 4 +- src/node/CMakeLists.txt | 8 + src/node/data/bn.cfg | 4 +- src/node/include/kth/node.hpp | 2 + .../kth/node/block_download_coordinator.hpp | 235 +++++++ .../node/block_download_coordinator_v2.hpp | 238 +++++++ .../include/kth/node/executor/executor.hpp | 4 + src/node/include/kth/node/parallel_sync.hpp | 44 ++ .../include/kth/node/parallel_sync_v2.hpp | 39 ++ src/node/include/kth/node/sync_session.hpp | 23 +- src/node/src/block_download_coordinator.cpp | 360 ++++++++++ .../src/block_download_coordinator_v2.cpp | 411 +++++++++++ src/node/src/executor/executor.cpp | 63 +- src/node/src/full_node.cpp | 104 ++- src/node/src/parallel_sync.cpp | 376 ++++++++++ src/node/src/parallel_sync_v2.cpp | 382 +++++++++++ src/node/src/parser.cpp | 4 +- src/node/src/sync_session.cpp | 366 +++++++--- tui_screenshot.png | Bin 0 -> 1232582 bytes 71 files changed, 5348 insertions(+), 494 deletions(-) create mode 100644 banlist.dat create mode 100644 docs/design/STRUCTURED_CONCURRENCY_DESIGN.md create mode 100644 docs/parallel-block-download.md create mode 100644 hosts.cache create mode 100644 src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp create mode 100644 src/node/include/kth/node/block_download_coordinator.hpp create mode 100644 src/node/include/kth/node/block_download_coordinator_v2.hpp create mode 100644 src/node/include/kth/node/parallel_sync.hpp create mode 100644 src/node/include/kth/node/parallel_sync_v2.hpp create mode 100644 src/node/src/block_download_coordinator.cpp create mode 100644 src/node/src/block_download_coordinator_v2.cpp create mode 100644 src/node/src/parallel_sync.cpp create mode 100644 src/node/src/parallel_sync_v2.cpp create mode 100644 tui_screenshot.png diff --git a/banlist.dat b/banlist.dat new file mode 100644 index 00000000..0e5abcaf --- /dev/null +++ b/banlist.dat @@ -0,0 +1 @@ +# Knuth banlist - format: IP create_time ban_until reason diff --git a/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md b/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md new file mode 100644 index 00000000..55effc3e --- /dev/null +++ b/docs/design/STRUCTURED_CONCURRENCY_DESIGN.md @@ -0,0 +1,383 @@ +# Structured Concurrency Design for Knuth Network Layer + +> **IMPORTANT**: This document is the source of truth for the network layer refactoring. +> Always read this document at the start of each session to understand the design goals. +> Location: `docs/design/STRUCTURED_CONCURRENCY_DESIGN.md` + +## Overview + +This document describes the refactoring of the Knuth network layer from "fire-and-forget" +coroutines (`::asio::detached`) to a structured concurrency model inspired by Go channels +and Kotlin coroutines. + +## Design Principles + +1. **No `::asio::detached`** except at the top-level entry point +2. **All coroutines must be awaited** - parent waits for all children +3. **Channel-based coordination** - Go-style message passing +4. **Separate IO and CPU executors** - maximize parallelism +5. **Graceful shutdown by design** - no race conditions + +## Current Problems + +```cpp +// PROBLEM: Fire-and-forget coroutines +::asio::co_spawn(executor, peer->run(), ::asio::detached); // Lost track! +::asio::co_spawn(executor, run_peer_protocols(peer), ::asio::detached); // Lost track! + +// PROBLEM: Race condition on shutdown +if (stopped()) { co_return; } // Check here... +co_await some_async_op(); // ...but stop() called here = crash +``` + +## Target Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ executor::run_async() │ +│ (single detached entry point) │ +│ ┌───────────────────────────────────────────────────────────────────┐ │ +│ │ full_node::run() │ │ +│ │ co_await ( │ │ +│ │ run_blockchain_subscriber() && │ │ +│ │ network_.run() && │ │ +│ │ run_sync() │ │ +│ │ ); │ │ +│ │ │ │ │ +│ │ ▼ │ │ +│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ +│ │ │ p2p_node::run() │ │ │ +│ │ │ co_await ( │ │ │ +│ │ │ run_inbound() && │ │ │ +│ │ │ run_outbound() && │ │ │ +│ │ │ peer_supervisor() ← manages all peer lifecycles │ │ │ +│ │ │ ); │ │ │ +│ │ └─────────────────────────────────────────────────────────────┘ │ │ +│ └───────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +## Key Components + +### 1. task_group (Nursery Pattern) + +New class to manage dynamic tasks without detached: + +```cpp +// File: src/infrastructure/include/kth/infrastructure/utility/task_group.hpp + +class task_group { +public: + explicit task_group(::asio::any_io_executor executor); + + // Spawn a task - tracked automatically + template + void spawn(Coro&& coro); + + // Spawn and get a handle to cancel later + template + task_handle spawn_with_handle(Coro&& coro); + + // Wait for ALL tasks to complete + ::asio::awaitable join(); + + // Cancel all tasks and wait + ::asio::awaitable cancel_and_join(); + + // Number of active tasks + size_t active_count() const; + +private: + ::asio::any_io_executor executor_; + std::atomic active_count_{0}; + ::asio::experimental::channel done_signal_; +}; +``` + +### 2. peer_supervisor + +Centralized peer lifecycle management: + +```cpp +// In p2p_node + +::asio::awaitable peer_supervisor() { + task_group peer_tasks(pool_.get_executor()); + + while (!stopped_) { + // Wait for new peer OR shutdown + auto event = co_await ( + new_peer_channel_.async_receive(::asio::use_awaitable) || + stop_signal_.async_receive(::asio::use_awaitable) + ); + + if (event.index() == 1) break; // shutdown + + auto [peer, direction] = std::get<0>(event); + + peer_tasks.spawn([this, peer]() -> ::asio::awaitable { + co_await peer->run_full(dispatcher_); + co_await manager_.remove(peer); + spdlog::debug("[p2p_node] Peer {} task completed", peer->authority()); + }); + } + + // CRITICAL: Wait for all peer tasks to finish + co_await peer_tasks.join(); +} +``` + +### 3. Unified peer_session::run_full() + +Single coroutine for entire peer lifecycle: + +```cpp +// In peer_session + +::asio::awaitable run_full(message_dispatcher& dispatcher) { + // All loops run in parallel, all must complete + co_await ( + read_loop() && + write_loop() && + run_protocols(dispatcher) && + inactivity_monitor() && + expiration_monitor() + ); +} +``` + +### 4. Channel-based Coordination + +```cpp +// New channels in p2p_node +struct { + // New peers to be supervised + concurrent_channel new_peer_channel_; + + // Shutdown signal + concurrent_channel stop_signal_; + +} channels_; + +// peer_event structure +struct peer_event { + peer_session::ptr peer; + enum class direction { inbound, outbound } dir; +}; +``` + +### 5. Separate CPU Executor + +```cpp +// For CPU-bound work (validation, etc.) +class cpu_executor { +public: + explicit cpu_executor(size_t threads = std::thread::hardware_concurrency()); + + template + auto post(F&& work) -> ::asio::awaitable>; + + void stop(); + void join(); + +private: + ::asio::thread_pool pool_; +}; +``` + +## Implementation Phases + +### Phase 1: Infrastructure ✅ COMPLETE +- [x] Make `run_inbound()` and `run_outbound()` awaited in `p2p_node::run()` +- [x] Make `full_node::run()` use `&&` operator for parallel tasks +- [x] Create `task_group` class (`src/infrastructure/.../utility/task_group.hpp`) +- [x] Create `cpu_executor` class (`src/infrastructure/.../utility/cpu_executor.hpp`) + +### Phase 2: Peer Lifecycle Refactoring ✅ COMPLETE +- [x] Add `new_peer_channel_` and `stop_signal_` to p2p_node +- [x] Implement `peer_supervisor()` with task_group +- [x] Modify `connect()` to send peer_event to channel with response channel +- [x] Modify `run_inbound()` to send peer_event to channel +- [x] Eliminate `peer->run()` detached spawns using `&&` operator pattern + - supervisor does: `peer->run() && (handshake && add && protocols)` + - connect() waits for handshake result via response channel + +### Phase 3: Connection Management ✅ COMPLETE +- [x] Refactor `run_inbound()` to send new peers to channel (done in Phase 2) +- [x] Refactor `maintain_outbound_connections()` to use task_group for parallel connects +- [x] Refactor seeding to use task_group + +### Phase 4: Cleanup ✅ COMPLETE +- [x] Fix `stop_all()` to NOT clear peers_ map (let remove() handle cleanup) +- [x] Remove `stopped()` check from `remove()` and `remove_by_nonce()` +- [x] Remove all `::asio::detached` from p2p_node.cpp (using `&&` operator pattern) +- [ ] Remove remaining `stopped()` checks from query methods (optional - they're defensive) +- [ ] Update tests + +### Phase 5: CPU Parallelism +- [ ] Integrate `cpu_executor` for block validation +- [ ] Add parallel header validation +- [ ] Add parallel transaction validation + +## Files to Modify + +| File | Changes | +|------|---------| +| `src/infrastructure/.../utility/task_group.hpp` | **DONE** - task_group class | +| `src/infrastructure/.../utility/cpu_executor.hpp` | **DONE** - CPU executor | +| `src/network/include/kth/network/p2p_node.hpp` | Add channels, peer_supervisor | +| `src/network/src/p2p_node.cpp` | Refactor connect/inbound/outbound | +| `src/network/include/kth/network/peer_session.hpp` | Add run_full() | +| `src/network/src/peer_session.cpp` | Implement run_full() | +| `src/network/src/peer_manager.cpp` | Remove stopped() checks | +| `src/node/src/full_node.cpp` | Already done - uses && | + +## Message Flow (Go-style) + +``` + ┌─────────────────┐ + │ run_inbound() │ + │ (accept loop) │ + └────────┬────────┘ + │ new peer + ▼ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ run_outbound() │───▶│ new_peer_channel│◀───│ connect() │ +│ (connect loop) │ └────────┬────────┘ │ (manual peer) │ +└─────────────────┘ │ └─────────────────┘ + ▼ + ┌─────────────────────┐ + │ peer_supervisor() │ + │ │ + │ task_group { │ + │ peer1.run_full() │ + │ peer2.run_full() │ + │ peer3.run_full() │ + │ ... │ + │ } │ + └─────────────────────┘ + │ + ▼ on stop() + ┌─────────────────────┐ + │ task_group.join() │ + │ (wait for all) │ + └─────────────────────┘ +``` + +## Shutdown Sequence + +``` +1. stop() called + │ + ├─▶ stop_signal_.send() // Signal supervisor to stop accepting + ├─▶ acceptor_.close() // Stop accepting new connections + └─▶ manager_.stop_all() // Signal all peers to stop + +2. peer_supervisor() receives stop_signal_ + │ + └─▶ Exits while loop, calls peer_tasks.join() + │ + └─▶ Waits for ALL peer->run_full() to complete + │ + └─▶ Each peer: socket closes → loops exit → run_full() returns + +3. run_inbound() exits (acceptor closed) + +4. run_outbound() exits (stopped_ = true) + +5. p2p_node::run() returns (all && branches completed) + +6. full_node::run() returns + +7. executor cleans up io_context + +NO RACE CONDITIONS - everything is awaited! +``` + +## Testing Strategy + +1. **Unit tests for task_group** + - spawn/join behavior + - cancel_and_join behavior + - exception propagation + +2. **Integration tests** + - Clean shutdown with active peers + - Shutdown during connection attempts + - Shutdown during handshake + +3. **Stress tests** + - Many concurrent connections + - Rapid connect/disconnect cycles + - Shutdown under load + +## References + +- [Trio Structured Concurrency](https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning) +- [Kotlin Structured Concurrency](https://kotlinlang.org/docs/coroutines-basics.html#structured-concurrency) +- [ASIO Awaitable Operators](https://think-async.com/Asio/asio-1.28.0/doc/asio/overview/composition/cpp20_coroutines.html) + +## Notes + +- The `&&` operator from `asio::experimental::awaitable_operators` runs coroutines + in parallel and waits for ALL to complete +- The `||` operator runs coroutines in parallel and completes when ANY finishes +- Channels use `asio::experimental::concurrent_channel` for thread-safety +- All peers share the same thread pool (`p2p_node::pool_`) + +## Remaining `::asio::detached` Uses + +These are the remaining detached uses in the codebase (excluding tests): + +### Legitimate / By Design + +| File | Location | Justification | +|------|----------|---------------| +| `task_group.hpp:97` | `spawn()` | Core mechanism - tasks are TRACKED via `active_count_` | +| `task_group.hpp:191` | `scoped_task_group` destructor | RAII blocking wait - expected behavior | +| `executor.cpp:232` | `stop_async()` | Top-level entry point from sync code (signal handlers) | + +### DEFERRED (Requires Restructuring) ✅ COMPLETE + +All `peer->run()` detached spawns have been eliminated using the `&&` operator pattern: + +| File | Location | Solution | +|------|----------|----------| +| `p2p_node.cpp` | `connect()` | Sends to supervisor, waits for handshake via response channel | +| `p2p_node.cpp` | `connect_to_seed()` | Uses `peer->run() && seeding_protocol()` directly | +| `p2p_node.cpp` | `run_inbound()` | Sends to supervisor (no wait needed for inbound) | +| `p2p_node.cpp` | `peer_supervisor()` | Uses `peer->run() && (handshake && add && protocols)` | + +**Pattern used**: The `&&` operator runs both coroutines in parallel. When peer disconnects, +both `run()` and the protocol branch exit, and `&&` completes. No detached needed! + +```cpp +// Structured concurrency pattern for peer lifecycle +peer_tasks.spawn([...]() -> awaitable { + co_await ( + peer->run() && // Message pump runs in parallel + [&]() -> awaitable { + co_await perform_handshake(*peer); // Uses channels (run() is running!) + co_await run_protocols(peer); + }() + ); // Both complete when peer disconnects +}); +``` + +## Future Work + +### High Priority +- [x] ~~Eliminate `peer->run()` detached spawns~~ ✅ COMPLETE + +### Medium Priority +- [ ] Review C API (`src/c-api/`) for structured concurrency patterns +- [ ] Update tests to use structured concurrency where applicable + +### Low Priority +- [ ] Consider making `executor::stop_async()` awaitable +- [ ] Add exception propagation to `task_group` + +--- + +**Last Updated**: 2025-12-22 +**Branch**: `feat/structured-concurrency` diff --git a/docs/parallel-block-download.md b/docs/parallel-block-download.md new file mode 100644 index 00000000..8dfb5a4d --- /dev/null +++ b/docs/parallel-block-download.md @@ -0,0 +1,567 @@ +# Parallel Block Download - Design Document + +## Problem Statement + +Current block download is sequential: request block N, wait for response, request block N+1. +With ~100ms round-trip latency, this limits throughput to ~10 blocks/second regardless of bandwidth. + +**Goal**: Download blocks in parallel from multiple peers to maximize throughput. + +## BCHN Reference Implementation + +BCHN uses a **centralized coordinator** with these parameters: + +```cpp +MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16 // per-peer pipeline depth +BLOCK_DOWNLOAD_WINDOW = 1024 // global look-ahead window +``` + +Key data structures: +- `mapBlocksInFlight`: global multimap (hash → peer_id) tracking ALL in-flight blocks +- `vBlocksInFlight`: per-peer list of blocks being downloaded + +Coordination logic: +1. For each peer, periodically check if `vBlocksInFlight.size() < 16` +2. Call `FindNextBlocksToDownload()` which skips blocks already in `mapBlocksInFlight` +3. Send single `getdata` with multiple block inventories +4. On block received: remove from tracking, process, loop automatically refills + +## Our Design: Block Download Coordinator + +### Architecture + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ BlockDownloadCoordinator │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ Shared State │ │ +│ │ - next_height_to_assign: atomic │ │ +│ │ - blocks_in_flight: map │ │ +│ │ - pending_blocks: map (out-of-order buffer) │ │ +│ │ - next_height_to_validate: uint32_t │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Peer 1 │ │ Peer 2 │ │ Peer 3 │ │ Peer N │ │ +│ │ in_flight: │ │ in_flight: │ │ in_flight: │ │ in_flight: │ │ +│ │ [h1,h2,h3] │ │ [h4,h5,h6] │ │ [h7,h8,h9] │ │ [...] │ │ +│ │ max: 16 │ │ max: 16 │ │ max: 16 │ │ max: 16 │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ Validation Pipeline │ │ +│ │ Processes blocks in order as they become available │ │ +│ │ next_height_to_validate → chain_.organize() │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Configuration + +```cpp +struct download_config { + size_t max_blocks_per_peer = 16; // pipeline depth per peer + size_t global_window = 1024; // max look-ahead + size_t target_peers = 8; // desired concurrent peers + std::chrono::seconds block_timeout = 60s; + std::chrono::seconds stall_timeout = 10s; +}; +``` + +### Core Components + +#### 1. BlockDownloadCoordinator + +Central coordinator that manages block assignments across peers. + +```cpp +class BlockDownloadCoordinator { +public: + // Called by sync_session to get next blocks to download + std::vector claim_blocks( + peer_session& peer, + size_t max_count // typically 16 + ); + + // Called when a block is received + void block_received( + hash_digest const& hash, + uint32_t height, + domain::message::block block + ); + + // Called when peer disconnects - reassign its blocks + void peer_disconnected(peer_session const& peer); + + // Called periodically to check for stalled downloads + void check_timeouts(); + + // Get next validated block for chain (blocks until available or timeout) + awaitable> next_validated_block(); + +private: + std::mutex mutex_; + + // Assignment tracking + uint32_t start_height_; + uint32_t target_height_; + std::atomic next_height_to_assign_; + + // In-flight tracking: height -> {peer, request_time, hash} + struct Assignment { + peer_session::ptr peer; + std::chrono::steady_clock::time_point requested_at; + hash_digest hash; + }; + std::map in_flight_; + + // Out-of-order buffer: height -> block + std::map pending_blocks_; + + // Validation state + uint32_t next_height_to_validate_; + + // Channel for validation pipeline + concurrent_channel validated_blocks_; +}; +``` + +#### 2. Peer Download Coroutine + +Each peer runs a download coroutine that: +1. Claims blocks from coordinator +2. Sends batch `getdata` +3. Receives blocks and reports to coordinator +4. Repeats + +```cpp +::asio::awaitable peer_download_loop( + peer_session::ptr peer, + BlockDownloadCoordinator& coordinator +) { + while (!stopped_ && peer->connected()) { + // Claim up to 16 blocks + auto blocks = coordinator.claim_blocks(*peer, 16); + if (blocks.empty()) { + // No more blocks or window full + co_await async_sleep(100ms); + continue; + } + + // Send batch getdata + co_await send_getdata(peer, blocks); + + // Receive blocks (with timeout) + for (size_t i = 0; i < blocks.size(); ++i) { + auto result = co_await receive_block_with_timeout(peer, 30s); + if (!result) { + // Timeout or error - coordinator will reassign + break; + } + coordinator.block_received(result->hash, result->height, std::move(*result)); + } + } +} +``` + +#### 3. Validation Pipeline + +Separate coroutine that processes blocks in order: + +```cpp +::asio::awaitable validation_pipeline( + BlockDownloadCoordinator& coordinator, + blockchain::block_chain& chain +) { + while (!stopped_) { + auto block = co_await coordinator.next_validated_block(); + if (!block) break; + + auto ec = co_await chain.organize(*block); + if (ec) { + // Handle validation failure + spdlog::error("Block validation failed at height {}", block->height()); + } + } +} +``` + +### Coordination Strategies + +#### Option A: Centralized (BCHN-style) + +``` +Coordinator assigns blocks sequentially: + Peer 1 gets: [1, 2, 3, ..., 16] + Peer 2 gets: [17, 18, 19, ..., 32] + Peer 3 gets: [33, 34, 35, ..., 48] + +As blocks complete, refill to maintain 16 per peer. +``` + +**Pros**: Simple, predictable, good locality +**Cons**: Single point of coordination + +#### Option B: Work Stealing (Decentralized) + +``` +Each peer claims ranges atomically: + next_to_claim.fetch_add(16) → gets exclusive range + +If peer stalls, others can "steal" unclaimed work. +``` + +**Pros**: Less contention, self-balancing +**Cons**: More complex, potential for gaps + +#### Option C: Hybrid (Recommended) + +``` +1. Coordinator assigns contiguous ranges to peers +2. Each peer manages its own in-flight window +3. On timeout/disconnect, coordinator reassigns to fastest peer +4. Adaptive: assign more blocks to faster peers +``` + +### Handling Edge Cases + +#### 1. Peer Disconnection + +```cpp +void BlockDownloadCoordinator::peer_disconnected(peer_session const& peer) { + std::lock_guard lock(mutex_); + + // Find all blocks assigned to this peer + std::vector to_reassign; + for (auto& [height, assignment] : in_flight_) { + if (assignment.peer.get() == &peer) { + to_reassign.push_back(height); + } + } + + // Move back to unassigned pool + for (auto height : to_reassign) { + in_flight_.erase(height); + // Will be claimed by next peer that asks + } +} +``` + +#### 2. Stalled Downloads + +```cpp +void BlockDownloadCoordinator::check_timeouts() { + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(mutex_); + + for (auto it = in_flight_.begin(); it != in_flight_.end(); ) { + if (now - it->second.requested_at > stall_timeout_) { + spdlog::warn("Block {} stalled from peer {}", + it->first, it->second.peer->authority()); + + // Ban slow peer or just reassign? + // For now, just reassign + it = in_flight_.erase(it); + } else { + ++it; + } + } +} +``` + +#### 3. Out-of-Order Blocks + +```cpp +void BlockDownloadCoordinator::block_received( + hash_digest const& hash, + uint32_t height, + block_ptr block +) { + std::lock_guard lock(mutex_); + + // Remove from in-flight + in_flight_.erase(height); + + if (height == next_height_to_validate_) { + // Perfect - validate immediately + validated_blocks_.try_send({}, std::move(block)); + ++next_height_to_validate_; + + // Check if we can validate more from pending + while (auto it = pending_blocks_.find(next_height_to_validate_); + it != pending_blocks_.end()) { + validated_blocks_.try_send({}, std::move(it->second)); + pending_blocks_.erase(it); + ++next_height_to_validate_; + } + } else { + // Out of order - buffer it + pending_blocks_[height] = std::move(block); + } +} +``` + +### Multi-Peer Orchestration + +```cpp +::asio::awaitable parallel_block_sync( + blockchain::block_chain& chain, + p2p_node& network, + uint32_t start_height, + uint32_t target_height +) { + BlockDownloadCoordinator coordinator(start_height, target_height); + + // Get all connected peers + auto peers = co_await network.peers().all(); + if (peers.empty()) { + co_return sync_result{error::no_peers}; + } + + // Create task group for all download coroutines + task_group download_tasks(network.thread_pool().get_executor()); + + // Spawn download loop for each peer + for (auto& peer : peers) { + download_tasks.spawn([&peer, &coordinator]() -> awaitable { + co_await peer_download_loop(peer, coordinator); + }); + } + + // Spawn validation pipeline + download_tasks.spawn([&coordinator, &chain]() -> awaitable { + co_await validation_pipeline(coordinator, chain); + }); + + // Spawn timeout checker + download_tasks.spawn([&coordinator]() -> awaitable { + while (!coordinator.complete()) { + co_await async_sleep(1s); + coordinator.check_timeouts(); + } + }); + + // Wait for all to complete + co_await download_tasks.join(); + + co_return sync_result{error::success, target_height - start_height}; +} +``` + +### Performance Expectations + +| Peers | Blocks/peer | Total In-Flight | Theoretical Speedup | +|-------|-------------|-----------------|---------------------| +| 1 | 16 | 16 | 16x | +| 4 | 16 | 64 | 64x | +| 8 | 16 | 128 | 128x | + +With 100ms latency and 16 blocks in-flight per peer: +- Single peer: 16 blocks / 100ms = 160 blocks/sec +- 8 peers: 128 blocks / 100ms = 1280 blocks/sec + +Actual throughput limited by: +- Bandwidth (block size × blocks/sec) +- Validation speed (CPU-bound) +- Disk I/O + +### Implementation Plan + +1. **Phase 1: BlockDownloadCoordinator class** + - Block assignment logic + - In-flight tracking + - Out-of-order buffering + +2. **Phase 2: Peer download coroutines** + - Batch getdata sending + - Block receiving with timeout + - Integration with coordinator + +3. **Phase 3: Validation pipeline** + - Ordered block processing + - Chain integration + +4. **Phase 4: Adaptive optimizations** + - Peer speed tracking + - Dynamic block assignment + - Slow peer detection + +### File Structure + +``` +src/node/ +├── block_download_coordinator.hpp +├── block_download_coordinator.cpp +├── parallel_sync.hpp +├── parallel_sync.cpp +└── sync_session.cpp (modified to use coordinator) +``` + +### Open Questions + +1. **Should we download from peers we're not fully connected to?** + - BCHN requires handshake complete before requesting blocks + +2. **How to handle forks/reorgs during download?** + - Need to validate headers first, then download blocks for winning chain + +3. **Memory limits for out-of-order buffer?** + - With 1024 window and avg 1MB blocks, could need 1GB buffer + - Consider disk-based buffering for large syncs + +4. **Prioritize recent blocks?** + - During IBD, oldest blocks first + - After IBD, newest blocks (for tip) should have priority + +--- + +## Implementation Status + +### Completed +- [x] `block_download_coordinator` class with parallel download management +- [x] `parallel_sync` orchestration with task_group (nursery pattern) +- [x] Integration with `sync_session` (automatic when p2p_node available) +- [x] Peer download loops with claim/receive pattern +- [x] Validation pipeline (in-order block validation) +- [x] Timeout checker for stalled downloads +- [x] Out-of-order buffering with flush to validation +- [x] Uses `boost::unordered_flat_map` for performance + +### Pending Optimizations + +1. **Batch getdata** (High Priority) + - Current: Each peer sends getdata one block at a time, waits for response + - Optimal: Send batch getdata (16 blocks), receive blocks via message handler + - Requires: New `receive_block_with_timeout()` function in `protocols_coro.hpp` + - Impact: Would reduce round-trip latency by ~16x per peer + +2. **Expose configuration in settings** (Medium Priority) + - Currently: `parallel_download_config` has hardcoded values + - TODO: Add to `node::settings` for user configuration + - Parameters: `max_blocks_per_peer`, `global_window`, `stall_timeout` + +3. **Dynamic memory limits** (Medium Priority) + - Issue: With window=1024 and ~1MB avg blocks, could use ~1GB in worst case + - TODO: Calculate `global_window` based on available system memory + - Consider: Disk-based buffering for very large syncs + +4. **Refactor coordinator to eliminate mutex** (Low Priority) + - Current: Uses `std::mutex` for thread-safe state access + - Alternatives to explore: + - Strand-based serialization (make `claim_blocks` awaitable) + - Actor model with command channel + - Note: Current mutex is acceptable due to low contention (~128 ops/sec) + +5. **Adaptive peer assignment** (Future Enhancement) + - Track peer download speeds + - Assign more blocks to faster peers + - Automatically deprioritize slow peers + +6. **Penalize slow peers** (Future Enhancement) + - If a peer consistently times out, reduce their block allocation + - Consider temporary banning for very slow peers + +--- + +## TODO: Parallel Validation Discussion + +### Current State: Sequential Validation + +Currently, validation happens sequentially: block N must be fully validated before block N+1. + +``` +Download: [====1====] [====2====] [====3====] [====4====] (parallel) +Validation: [====1====][====2====][====3====][====4====] (sequential) +``` + +### What CAN be parallelized? + +1. **Syntax/Format Validation** + - Block header format + - Transaction format + - Merkle root calculation + - Size limits + - These are independent per block + +2. **Script Validation (Signature Checks)** + - ECDSA/Schnorr signature verification is CPU-intensive + - Scripts within a block can be validated in parallel + - Scripts across blocks can potentially be validated in parallel (with caveats) + +3. **PoW Validation** + - Header hash < target + - Independent per block + +### What MUST be sequential? + +1. **UTXO Set Updates** + - Block N creates outputs that block N+1 might spend + - Must apply in order to maintain consistency + +2. **Contextual Validation** + - Coinbase maturity (100 blocks) + - Median time past + - Difficulty adjustment + - BIP activation heights + +### Proposed Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Download Phase │ +│ Peer1: [blk 100-115] Peer2: [blk 116-131] Peer3: [...] │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Pre-Validation (Parallel) │ +│ - Syntax checks │ +│ - Merkle root │ +│ - PoW validation │ +│ - Script validation (signatures) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Contextual Validation (Sequential) │ +│ - UTXO lookups and updates │ +│ - Coinbase maturity │ +│ - Median time past │ +│ - Connect to chain │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Questions to Discuss + +1. **Script validation across blocks**: + - Can we validate scripts for block N+1 while block N is being connected? + - Need to handle the case where N+1 spends an output created in N + +2. **Batch signature verification**: + - Schnorr signatures can be batch-verified (faster than individual) + - How to accumulate signatures across blocks? + +3. **UTXO cache strategy**: + - Pre-fetch UTXOs for upcoming blocks? + - Speculative execution with rollback? + +4. **Thread pool sizing**: + - How many threads for script validation? + - Separate pools for download vs validation? + +5. **Assumevalid optimization**: + - Skip script validation for blocks before a known-good hash + - Bitcoin Core uses this for faster IBD + +### References + +- BCHN parallel validation: `src/validation.cpp` +- Bitcoin Core `CheckInputScripts` parallelization +- libsecp256k1 batch verification + +--- + +## Discussion Notes + +(Add notes here as we discuss) diff --git a/hosts.cache b/hosts.cache new file mode 100644 index 00000000..a34d9f6e --- /dev/null +++ b/hosts.cache @@ -0,0 +1,645 @@ +23.191.200.9:19798 +65.21.79.59:8333 +101.69.226.138:8333 +35.193.139.211:8333 +94.25.187.239:8333 +75.164.137.188:8433 +83.221.211.116:8333 +143.105.117.74:8330 +70.57.97.122:8333 +212.8.248.197:8333 +31.10.157.171:8333 +45.84.107.200:8333 +116.75.149.83:8333 +109.93.234.55:8339 +116.74.192.64:8333 +185.246.188.149:9663 +45.144.113.253:8333 +109.139.30.102:8336 +158.220.122.39:8333 +85.244.4.208:6335 +82.118.248.205:19798 +185.220.101.24:19798 +116.202.196.52:8333 +143.244.44.175:8333 +104.244.76.237:8333 +23.137.105.248:8333 +157.230.21.198:8333 +185.207.251.50:8333 +91.236.251.138:8333 +209.141.55.26:9333 +69.218.225.129:8333 +102.90.82.109:8333 +167.179.172.173:8333 +154.216.19.10:8334 +34.217.76.29:8333 +1.4.200.149:8333 +136.42.232.7:8333 +176.126.62.152:8333 +176.52.54.126:6335 +194.14.247.36:8333 +54.180.166.112:8333 +72.50.7.43:8333 +185.220.101.181:19798 +75.128.230.115:6335 +108.35.251.240:6335 +219.117.244.105:8333 +114.216.223.123:8333 +2.94.60.118:8333 +187.87.106.4:9333 +193.32.249.217:65001 +1.156.22.158:64454 +85.249.29.39:6335 +118.166.149.5:8333 +84.66.121.155:8333 +149.19.165.195:8333 +212.171.102.227:8333 +185.209.199.95:65001 +198.98.50.112:9333 +54.65.62.127:8333 +96.21.47.54:9333 +23.234.119.118:8333 +193.189.100.206:8333 +107.172.34.196:8333 +78.46.240.210:8333 +198.102.229.253:8333 +202.53.49.202:8333 +35.79.107.85:47963 +95.217.111.35:11011 +5.188.104.245:8339 +173.216.88.59:14522 +212.241.24.147:8333 +183.4.133.120:8333 +191.204.194.52:8333 +79.40.32.207:8333 +49.13.32.144:8333 +213.55.184.49:8333 +47.128.228.87:8334 +5.255.101.131:8333 +178.165.128.167:30008 +216.24.210.151:8333 +54.251.211.75:8333 +143.105.209.32:8333 +37.120.174.180:8333 +185.220.101.50:19798 +185.246.188.74:10333 +165.227.84.200:8963 +133.167.82.173:8333 +147.81.26.71:8333 +134.101.190.231:8333 +54.178.159.239:8333 +216.8.181.249:8333 +185.129.61.8:8333 +54.250.184.95:8333 +176.52.52.4:6335 +91.141.36.118:8333 +87.78.190.15:8333 +172.56.168.149:19665 +119.111.231.247:8333 +152.37.136.203:8333 +79.195.74.220:8323 +135.181.219.10:8433 +54.219.188.176:49088 +39.190.99.154:8333 +185.40.4.127:8333 +18.197.132.221:8333 +172.56.249.36:8333 +54.39.104.128:8333 +109.213.253.48:8333 +23.129.64.198:8333 +87.249.138.133:8333 +177.140.105.178:8335 +151.68.90.113:8333 +152.53.90.71:8333 +81.183.200.65:8337 +4.189.92.202:8333 +95.216.119.109:38333 +45.143.200.32:8333 +203.12.0.126:8333 +150.221.202.248:8333 +128.73.93.121:8333 +173.249.205.122:8334 +84.153.21.72:8335 +46.114.203.255:8333 +144.76.92.36:28333 +185.31.136.173:8333 +81.183.141.187:8333 +8.217.33.31:8333 +111.251.101.180:8333 +81.154.39.95:8333 +129.224.201.176:8333 +78.47.121.92:202 +81.22.58.61:8333 +2.248.89.180:8333 +172.56.11.31:8333 +178.2.151.43:29333 +136.243.147.220:9002 +106.157.175.170:8333 +31.25.241.224:8339 +182.0.236.85:8333 +61.230.95.209:8333 +222.219.107.46:8333 +27.56.141.31:8333 +93.197.37.62:8323 +144.6.96.5:8333 +79.24.244.4:8333 +115.69.29.15:6335 +185.220.101.36:10333 +185.40.4.143:8333 +95.222.185.37:8323 +91.202.26.23:8362 +123.114.100.23:2101 +203.210.222.199:8333 +164.92.120.45:8339 +147.93.156.254:8333 +144.172.118.73:8334 +66.23.234.238:8334 +185.241.208.82:19798 +160.19.35.103:8333 +185.181.60.205:19798 +172.111.156.147:8333 +85.16.0.35:8333 +64.176.47.71:8333 +156.155.10.161:7333 +64.20.53.98:8335 +23.129.64.144:8333 +45.141.215.133:19798 +81.183.139.101:9333 +178.5.111.105:28333 +144.126.141.74:8333 +23.129.64.135:8334 +185.220.101.52:8333 +146.103.43.17:7333 +223.165.102.145:8333 +94.142.241.194:19798 +49.205.106.2:8333 +185.233.100.23:19798 +95.168.105.17:8333 +175.0.57.75:8333 +185.220.101.138:8333 +54.36.209.253:8334 +208.88.16.4:8333 +188.252.166.114:8321 +71.36.122.7:8433 +79.195.69.55:8323 +185.233.93.90:8333 +92.40.170.213:8333 +73.136.36.125:8333 +201.203.117.131:8333 +149.50.218.2:8333 +107.159.8.144:8333 +138.255.59.207:8333 +46.38.238.151:12000 +129.222.192.205:8333 +50.255.99.93:7870 +105.108.148.122:19798 +34.12.224.117:31109 +144.172.118.4:19798 +37.192.75.27:8333 +223.204.71.13:8333 +18.167.190.106:48235 +23.129.64.149:19798 +64.31.58.10:8333 +213.244.206.128:6335 +217.138.219.184:8334 +213.55.185.202:8333 +185.120.89.98:8333 +209.127.122.140:19798 +36.234.205.244:8333 +15.204.52.161:8333 +221.216.137.25:8433 +46.22.5.151:8333 +45.119.84.253:8333 +66.115.146.165:8333 +191.96.150.146:8333 +205.185.113.8:8333 +8.219.86.245:8333 +35.214.103.89:8333 +188.245.217.12:8333 +23.234.71.20:8333 +185.247.194.11:8333 +79.249.188.66:8334 +104.244.79.50:8333 +213.55.184.221:8333 +34.201.132.121:18333 +206.83.114.186:8333 +121.9.181.203:8333 +98.46.105.159:6335 +107.174.71.36:8333 +37.222.245.79:8333 +84.216.194.47:8333 +204.8.96.87:19798 +185.129.62.62:9663 +114.16.18.46:8333 +35.197.99.186:31553 +45.12.111.14:8333 +142.162.9.64:8336 +79.191.99.133:38333 +23.129.64.148:19798 +93.219.208.140:8333 +104.28.228.84:19798 +91.64.72.85:8334 +185.253.183.177:8333 +149.233.239.233:8333 +209.141.34.15:8333 +171.250.121.34:8333 +176.65.134.4:19798 +98.97.39.109:8993 +32.218.131.61:8333 +144.202.5.150:7870 +34.84.123.7:8333 +172.59.185.203:8333 +98.97.27.110:8332 +202.184.104.12:8333 +210.211.61.46:8333 +185.220.101.145:8334 +136.23.10.75:8333 +223.204.216.12:8333 +182.171.102.226:8333 +185.220.101.101:8334 +94.114.117.150:9333 +83.39.163.77:8333 +97.120.0.147:8433 +188.252.166.68:8321 +213.239.204.59:8333 +86.110.236.37:6335 +94.26.249.13:8333 +178.162.138.104:8333 +176.52.57.22:6335 +143.105.151.73:8333 +116.202.241.54:13011 +174.91.231.74:8333 +3.147.82.109:61132 +135.129.113.35:8333 +23.249.26.172:8333 +45.90.185.108:8333 +5.78.24.87:8333 +201.203.117.12:8333 +3.238.219.148:8333 +114.10.117.217:8333 +159.100.240.67:8333 +57.129.84.149:8313 +93.219.223.194:8333 +81.154.39.56:8333 +20.89.134.133:8333 +185.213.154.83:8334 +85.194.204.85:8333 +23.191.200.11:19798 +149.224.0.102:8333 +104.182.218.53:8333 +194.233.174.56:8334 +13.212.246.16:8333 +45.234.213.59:6335 +116.74.199.154:8333 +86.98.180.214:8333 +185.220.101.175:8333 +89.244.90.227:9334 +146.0.75.226:1091 +85.93.218.204:19798 +98.97.26.163:8330 +156.146.51.80:10333 +185.220.101.140:9663 +37.19.198.37:8333 +154.251.104.203:9333 +107.172.143.67:8333 +194.99.104.35:8333 +57.129.84.149:8302 +198.252.125.136:8336 +123.181.162.53:6335 +78.51.70.154:8333 +45.86.200.138:8333 +185.225.232.34:8330 +105.109.136.241:19798 +152.58.60.125:8333 +36.234.219.216:8333 +109.123.55.242:8333 +24.52.248.184:28333 +213.91.128.133:8333 +35.189.84.195:8333 +43.225.189.109:8333 +193.26.115.140:9663 +194.26.192.161:8334 +104.224.120.212:8333 +185.220.101.162:8531 +38.242.254.131:19798 +94.49.30.83:8333 +37.138.165.59:8333 +185.250.38.13:8333 +181.214.165.28:8336 +98.97.37.76:8993 +86.151.48.209:8333 +193.116.225.53:8333 +93.197.40.172:8323 +34.245.64.155:5001 +142.171.106.238:8333 +45.94.208.25:8333 +207.246.85.175:7870 +23.94.220.130:8385 +13.115.38.57:8333 +77.48.28.204:19798 +79.117.129.96:8333 +146.70.117.212:19798 +209.141.55.26:19798 +149.22.108.171:8333 +162.19.7.11:8333 +92.40.219.109:8335 +116.74.195.151:8333 +72.50.4.54:8333 +98.167.206.49:8333 +114.243.97.86:8333 +51.81.184.86:37970 +178.127.27.238:8333 +216.174.70.77:8333 +92.60.40.205:19798 +57.129.18.162:8333 +35.80.222.198:8333 +46.114.92.181:8333 +5.9.56.139:8331 +90.151.86.27:8333 +64.31.58.34:8333 +176.52.57.80:6335 +176.65.149.195:8333 +217.182.198.163:8333 +173.249.58.36:8333 +188.165.37.58:8335 +37.60.231.59:19798 +37.60.229.178:8333 +129.213.76.88:8336 +74.80.182.70:8333 +103.91.65.44:19798 +70.51.240.228:8333 +18.182.192.156:8333 +134.122.93.73:8335 +75.164.145.241:8433 +168.119.162.233:8333 +142.132.136.223:8353 +134.209.237.2:8444 +46.114.244.154:8333 +182.8.226.243:8333 +185.220.101.14:8333 +208.115.211.114:8333 +129.222.194.7:8333 +54.219.188.176:48976 +18.201.212.198:5001 +67.43.230.26:8333 +185.138.88.25:8333 +129.222.195.123:8333 +80.94.92.92:8334 +120.244.194.109:8333 +86.102.40.50:8333 +174.127.145.82:8333 +188.252.166.192:8321 +209.141.40.68:8335 +45.170.114.167:6335 +185.220.101.57:19798 +77.174.124.44:8333 +185.220.101.16:19798 +45.84.107.172:8531 +203.55.81.1:19798 +104.167.242.118:8334 +172.93.221.151:8333 +85.190.254.126:8333 +134.101.220.101:8333 +94.25.168.142:8333 +34.139.57.123:8333 +14.203.85.225:8333 +64.219.160.116:6335 +207.225.131.170:6950 +89.157.2.223:8333 +58.7.215.137:10333 +199.199.199.32:8633 +88.99.225.141:8333 +95.217.246.229:8333 +115.220.182.102:8333 +149.40.62.55:10333 +54.195.221.110:8333 +185.197.250.105:8333 +116.74.192.123:8333 +156.229.232.115:9663 +79.25.225.65:8333 +185.220.101.176:9333 +118.166.147.91:8333 +83.217.13.198:8336 +46.114.169.110:8333 +222.129.37.84:3101 +23.191.200.9:8333 +209.198.131.41:8333 +194.15.112.133:8335 +54.219.188.176:17262 +116.74.184.254:8333 +116.74.196.145:8333 +47.156.34.225:6335 +36.234.231.145:8333 +146.70.211.19:8333 +194.54.144.97:8333 +45.83.220.216:8333 +85.208.139.110:19798 +167.114.119.46:8333 +114.223.221.47:8733 +82.77.102.212:10863 +47.128.78.31:8333 +159.196.169.50:18333 +5.255.117.56:10333 +34.124.164.210:8333 +20.82.44.15:7333 +190.56.195.67:8333 +162.247.74.27:9333 +5.255.99.147:19798 +185.238.121.58:8333 +64.130.45.91:8333 +178.165.186.211:30008 +79.141.163.112:8333 +138.84.36.210:8333 +111.248.218.228:8333 +149.224.82.172:8333 +81.222.190.97:6335 +185.254.196.141:19798 +129.222.196.90:8333 +178.122.206.166:8333 +206.83.112.191:8333 +5.2.79.190:8333 +111.199.186.107:3101 +176.83.49.14:8333 +162.247.72.192:10333 +93.197.47.15:8323 +120.40.199.117:8333 +83.22.193.219:8333 +193.26.115.140:8333 +114.24.138.118:8333 +109.202.110.57:8333 +58.84.61.31:8333 +174.89.243.132:8333 +116.74.175.129:8333 +5.35.69.163:8333 +95.71.167.224:8333 +37.45.160.173:8333 +185.220.101.82:19798 +121.43.153.48:8333 +77.183.178.1:8333 +195.176.3.24:19798 +24.1.77.227:8333 +46.114.242.176:8333 +51.91.80.241:8333 +185.220.101.48:531 +122.172.87.47:8333 +194.163.156.221:8333 +73.84.169.252:8333 +46.114.170.184:8333 +103.146.203.11:19798 +73.3.203.128:8333 +83.217.13.202:8336 +167.99.60.46:8332 +62.171.137.169:8333 +185.129.62.64:8334 +194.71.227.135:8334 +146.70.194.25:8333 +172.245.178.167:8333 +111.251.68.16:8333 +98.159.36.152:8333 +65.68.45.165:6335 +173.234.17.198:8333 +23.137.248.100:19798 +212.216.140.141:8333 +89.147.108.90:19798 +91.249.95.39:8333 +151.54.241.102:8333 +206.71.158.65:19798 +39.71.151.134:8333 +46.114.219.106:8333 +109.252.70.74:8333 +81.25.170.30:8333 +176.52.57.239:6335 +49.182.78.110:8333 +98.46.105.106:6335 +211.30.131.137:8333 +23.22.205.67:18333 +46.147.150.160:8333 +195.154.167.36:8333 +49.43.43.7:8333 +111.250.63.15:8333 +60.236.93.160:8333 +157.100.198.164:6335 +45.13.225.69:9663 +54.158.91.224:8333 +31.150.127.253:8333 +45.12.52.30:8333 +185.107.57.66:19798 +171.25.193.38:8333 +95.179.139.47:8333 +213.21.32.220:8333 +104.199.92.57:46964 +188.165.77.110:9333 +98.97.41.80:8993 +46.114.88.14:8333 +157.50.174.91:8333 +45.83.104.137:10333 +89.164.36.23:8333 +72.50.4.55:8333 +39.78.148.20:8333 +185.42.170.203:19798 +93.181.204.102:8333 +104.244.79.44:19798 +73.22.179.110:8333 +47.245.28.85:8333 +77.119.211.215:8333 +95.52.114.73:18333 +195.26.231.109:8373 +88.130.80.203:6335 +52.30.206.240:8333 +81.89.56.2:52964 +107.161.89.155:8385 +185.220.101.56:10333 +119.126.168.62:8333 +95.217.73.169:8333 +188.214.104.21:8334 +5.249.38.235:8333 +125.119.157.238:8333 +162.55.230.100:8333 +194.36.145.176:8333 +39.71.151.173:8333 +35.187.240.10:8333 +60.48.93.156:8333 +80.3.166.236:8333 +49.76.141.14:8733 +185.220.101.56:9333 +77.223.102.9:8333 +91.215.89.105:8333 +82.77.81.56:8333 +81.91.189.241:8133 +23.129.64.164:7333 +193.26.115.140:19798 +169.155.251.12:8333 +103.230.184.159:8333 +91.23.153.193:8323 +149.56.16.133:8333 +18.142.36.118:8333 +5.189.186.199:8333 +149.22.108.29:8333 +148.113.16.157:8333 +143.244.42.67:7333 +35.243.80.95:8333 +64.190.76.12:19798 +182.165.86.69:8333 +62.3.53.10:8435 +87.17.89.186:8334 +88.80.26.3:19798 +155.133.22.65:8333 +190.47.66.182:8333 +46.114.246.178:8333 +92.234.19.156:28333 +86.54.28.49:19798 +169.150.218.83:10333 +191.54.39.66:8333 +185.130.47.58:9333 +195.47.238.91:8333 +51.91.18.151:19798 +117.84.219.95:8733 +152.57.43.122:8333 +61.230.72.44:8333 +35.200.60.45:8333 +13.57.191.34:8333 +149.22.108.119:8333 +197.99.36.142:8333 +61.223.221.81:8333 +23.137.254.137:8334 +84.247.187.110:8333 +84.86.187.232:8333 +23.184.48.127:10333 +75.164.137.206:8433 +156.248.8.96:8333 +203.9.210.97:19798 +34.243.233.30:5001 +45.141.215.111:8334 +85.249.25.190:8333 +176.247.45.235:8333 +193.81.233.121:39388 +174.219.126.155:8333 +217.142.22.140:8333 +176.65.149.148:19798 +101.128.96.175:6335 +31.220.78.89:8333 +52.38.59.165:8333 +117.241.248.15:8333 +23.191.200.13:8334 +185.213.80.55:8333 +3.252.227.104:50072 +185.193.88.3:8338 +95.158.207.161:45833 +46.114.212.209:8333 +89.247.166.72:8333 +35.197.99.186:31341 +185.220.101.159:10333 +138.199.21.242:8333 +188.252.164.42:8321 +79.137.68.69:8333 +171.25.193.35:19798 +43.198.67.141:8333 +18.139.1.192:8333 +47.156.147.150:8333 +85.249.31.120:8333 +213.168.89.164:8333 +93.85.162.78:8333 +114.223.15.143:8733 +201.206.180.3:8333 +23.129.64.217:9333 +34.172.151.203:8333 diff --git a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp index c94932c1..1316e017 100644 --- a/src/blockchain/include/kth/blockchain/interface/block_chain.hpp +++ b/src/blockchain/include/kth/blockchain/interface/block_chain.hpp @@ -76,8 +76,9 @@ struct KB_API block_chain { // ORGANIZERS (Core blockchain operations) // ========================================================================= + /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable organize(block_const_ptr block); + ::asio::awaitable organize(block_const_ptr block, bool headers_pre_validated = false); [[nodiscard]] ::asio::awaitable organize(transaction_const_ptr tx); @@ -186,6 +187,7 @@ struct KB_API block_chain { [[nodiscard]] std::expected, database::result_code> get_transaction_position( hash_digest const& hash, bool require_confirmed) const; + [[nodiscard]] bool header_exists(hash_digest const& block_hash) const; [[nodiscard]] bool block_exists(hash_digest const& block_hash) const; // ========================================================================= diff --git a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp index cb0e78ae..369f3bd9 100644 --- a/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/block_organizer.hpp @@ -50,8 +50,9 @@ struct KB_API block_organizer { bool stop(); /// Organize a block - coroutine version + /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable organize(block_const_ptr block); + ::asio::awaitable organize(block_const_ptr block, bool headers_pre_validated = false); [[nodiscard]] block_broadcaster::channel_ptr subscribe(); diff --git a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp index 9cdce50a..34105a96 100644 --- a/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp +++ b/src/blockchain/include/kth/blockchain/pools/header_organizer.hpp @@ -124,10 +124,13 @@ struct KB_API header_organizer { bool stopped() const { return stopped_; } private: - // Validate a single header against expected previous + // Validate a single header with full chain-state validation + // Includes: PoW check, difficulty, checkpoint, version, MTP [[nodiscard]] - code validate(domain::chain::header const& header, int32_t height, - hash_digest const& previous) const; + code validate_full(domain::chain::header const& header, + hash_digest const& hash, + int32_t height, + header_index::index_t parent_idx) const; // Members header_index& index_; diff --git a/src/blockchain/include/kth/blockchain/settings.hpp b/src/blockchain/include/kth/blockchain/settings.hpp index 8cff1e78..79d4cd5b 100644 --- a/src/blockchain/include/kth/blockchain/settings.hpp +++ b/src/blockchain/include/kth/blockchain/settings.hpp @@ -32,6 +32,8 @@ struct KB_API settings { uint32_t notify_limit_hours = 24; uint32_t reorganization_limit = 256; infrastructure::config::checkpoint::list checkpoints; + infrastructure::config::checkpoint::list checkpoints_sorted; // Pre-sorted by height + size_t max_checkpoint_height = 0; // Pre-computed max bool fix_checkpoints = true; bool allow_collisions = true; bool easy_blocks = false; diff --git a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp index 800b6fe6..c8ad1b15 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_block.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_block.hpp @@ -41,15 +41,32 @@ struct KB_API validate_block { void start(); void stop(); + /// @param headers_pre_validated If true, skip header validation (for headers-first sync) [[nodiscard]] - ::asio::awaitable check(block_const_ptr block) const; + ::asio::awaitable check(block_const_ptr block, bool headers_pre_validated = false) const; + /// @param headers_pre_validated If true, use accept_body() to skip header validation [[nodiscard]] - ::asio::awaitable accept(branch::const_ptr branch) const; + ::asio::awaitable accept(branch::const_ptr branch, bool headers_pre_validated = false) const; [[nodiscard]] ::asio::awaitable connect(branch::const_ptr branch) const; + // ========================================================================= + // Static validation functions (pure, no side effects) + // These replace the accept/connect methods that were in block_basis. + // ========================================================================= + + /// Validate block body against chain state (skip header validation). + /// Validates: block size, transaction ordering, coinbase, finality. + /// @param block The block to validate. + /// @param state The chain state for context. + /// @return error::success or validation error. + [[nodiscard]] + static code accept_block_body( + domain::chain::block const& block, + domain::chain::chain_state const& state); + protected: [[nodiscard]] bool stopped() const { diff --git a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp index f7337579..eebf11b5 100644 --- a/src/blockchain/include/kth/blockchain/validate/validate_header.hpp +++ b/src/blockchain/include/kth/blockchain/validate/validate_header.hpp @@ -7,8 +7,10 @@ #include #include +#include #include +#include #include #include @@ -35,6 +37,10 @@ struct KB_API validate_header { /// @param[in] network The network type (mainnet, testnet, etc). validate_header(settings const& settings, domain::config::network network); + /// Access the settings. + [[nodiscard]] + settings const& chain_settings() const { return settings_; } + /// Context-free validation (PoW + timestamp). /// Validates: /// - Proof of work is valid for the claimed difficulty (bits) @@ -68,6 +74,67 @@ struct KB_API validate_header { code validate(domain::chain::header const& header, size_t height, hash_digest const& previous) const; + // ========================================================================= + // Full validation with header_index (for headers-first sync) + // ========================================================================= + + /// Full accept validation using header_index to build chain_state. + /// This performs complete header validation including: + /// - Chain continuity (previous block hash) + /// - Checkpoint validation + /// - Difficulty check (work_required) + /// - Version check (minimum_version) + /// - Median time past check + /// + /// @param[in] header The header to validate. + /// @param[in] hash The header's hash. + /// @param[in] height The height of this header. + /// @param[in] parent_idx Index of parent header in the index. + /// @param[in] index The header index containing historical data. + /// @return error::success or the validation error. + [[nodiscard]] + code accept_full(domain::chain::header const& header, + hash_digest const& hash, + size_t height, + header_index::index_t parent_idx, + header_index const& index) const; + + /// Build chain_state::data from header_index for a given height. + /// This collects the historical bits, versions, and timestamps needed + /// to construct a chain_state for validation. + /// + /// @param[in] height The target height. + /// @param[in] header The header at target height. + /// @param[in] hash The header's hash. + /// @param[in] parent_idx Index of parent header in the index. + /// @param[in] index The header index containing historical data. + /// @return chain_state::data populated from the index, or error code on failure. + [[nodiscard]] + std::expected build_chain_state_data( + size_t height, + domain::chain::header const& header, + hash_digest const& hash, + header_index::index_t parent_idx, + header_index const& index) const; + + // ========================================================================= + // Static validation functions (pure, no side effects) + // These can be called without a validate_header instance when chain_state + // is already available. + // ========================================================================= + + /// Validate header against chain state. + /// Validates: difficulty, checkpoint, version, MTP. + /// @param header The header to validate. + /// @param hash The header hash. + /// @param state The chain state for context. + /// @return error::success or validation error. + [[nodiscard]] + static code accept_header( + domain::chain::header const& header, + hash_digest const& hash, + domain::chain::chain_state const& state); + /// Check if a height is under checkpoint protection. /// Headers under checkpoint can skip some validation. [[nodiscard]] @@ -90,8 +157,24 @@ struct KB_API validate_header { [[nodiscard]] size_t last_checkpoint_height() const; + /// Collect historical data (bits, versions, timestamps) from header_index. + /// Single traversal for efficiency. + [[nodiscard]] + std::expected collect_historical_data( + domain::chain::chain_state::map const& map, + header_index::index_t parent_idx, + header_index const& index) const; + +#if defined(KTH_CURRENCY_BCH) + /// Get the ASERT anchor block info for the network. + [[nodiscard]] + domain::chain::chain_state::assert_anchor_block_info_t get_asert_anchor_block() const; +#endif + // Configuration + settings const& settings_; checkpoint_list const checkpoints_; + uint32_t const configured_forks_; domain::config::network const network_; bool const retarget_; // Whether PoW retargeting is enabled (mainnet=true) }; diff --git a/src/blockchain/src/interface/block_chain.cpp b/src/blockchain/src/interface/block_chain.cpp index 9385d6e4..08335974 100644 --- a/src/blockchain/src/interface/block_chain.cpp +++ b/src/blockchain/src/interface/block_chain.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -142,16 +143,69 @@ bool block_chain::start() { return false; } - // Initialize header_index with genesis block - auto const genesis = get_header(0); - if (genesis) { - auto const hash = genesis->hash(); - auto const [inserted, index, capacity_warning] = header_index_.add(hash, *genesis); - if ( ! inserted) { - spdlog::error("[blockchain] Failed to initialize header index with genesis block."); - return false; + // Load all headers from database into header_index + // This allows resuming sync from where we left off + auto const heights = get_last_heights(); + if ( ! heights) { + spdlog::error("[blockchain] Failed to get last heights from database."); + return false; + } + + auto const [header_height, block_height] = *heights; + spdlog::info("[blockchain] Database state: header_height={}, block_height={}", header_height, block_height); + + if (header_height == 0) { + // Only genesis in DB - just add genesis to index + auto const genesis = get_header(0); + if (genesis) { + auto const hash = genesis->hash(); + auto const [inserted, idx, capacity_warning] = header_index_.add(hash, *genesis); + if ( ! inserted) { + spdlog::error("[blockchain] Failed to initialize header index with genesis block."); + return false; + } + spdlog::info("[blockchain] Header index initialized with genesis: {}", encode_hash(hash)); } - spdlog::info("[blockchain] Header index initialized with genesis: {}", encode_hash(hash)); + } else { + // Load all headers from DB into header_index + spdlog::info("[blockchain] Loading {} headers from database into header_index...", header_height + 1); + + auto const load_start = std::chrono::steady_clock::now(); + + // Load in batches to avoid memory spikes + constexpr size_t batch_size = 10000; + size_t loaded = 0; + + for (size_t from = 0; from <= header_height; from += batch_size) { + auto const to = std::min(from + batch_size - 1, header_height); + auto const headers_result = get_headers(from, to); + + if ( ! headers_result) { + spdlog::error("[blockchain] Failed to load headers from {} to {}", from, to); + return false; + } + + size_t height = from; + for (auto const& header : *headers_result) { + auto const hash = header.hash(); + auto const [inserted, idx, capacity_warning] = header_index_.add(hash, header); + if ( ! inserted && height > 0) { + // Genesis might already be added, ignore that case + spdlog::warn("[blockchain] Failed to add header at height {} to index", height); + } + ++height; + ++loaded; + } + + // Log progress every 100k headers + if (loaded % 100000 < batch_size && loaded > 0) { + spdlog::info("[blockchain] Loaded {}/{} headers into index...", loaded, header_height + 1); + } + } + + auto const elapsed = std::chrono::steady_clock::now() - load_start; + auto const elapsed_ms = std::chrono::duration_cast(elapsed).count(); + spdlog::info("[blockchain] Loaded {} headers into header_index in {}ms", loaded, elapsed_ms); } return true; @@ -182,8 +236,8 @@ bool block_chain::stopped() const { // ORGANIZERS (Core blockchain operations) // ============================================================================= -::asio::awaitable block_chain::organize(block_const_ptr block) { - co_return co_await block_organizer_.organize(block); +::asio::awaitable block_chain::organize(block_const_ptr block, bool headers_pre_validated) { + co_return co_await block_organizer_.organize(block, headers_pre_validated); } ::asio::awaitable block_chain::organize(transaction_const_ptr tx) { @@ -405,7 +459,7 @@ std::expected, database::result_code> block_chain::get return std::unexpected(result.error()); } auto const& [header_height, block_height] = *result; - return std::pair{static_cast(header_height), static_cast(block_height)}; + return std::pair{size_t(header_height), size_t(block_height)}; } std::expected block_chain::get_header(size_t height) const { @@ -460,16 +514,39 @@ std::expected block_chain::get_block_hash(si return result->hash(); } -bool block_chain::block_exists(hash_digest const& block_hash) const { +bool block_chain::header_exists(hash_digest const& block_hash) const { return database_.internal_db().get_header(block_hash).has_value(); } +bool block_chain::block_exists(hash_digest const& block_hash) const { + // Check if full block exists (not just header) + // With headers-first sync, headers may exist without full blocks + auto const header_result = database_.internal_db().get_header(block_hash); + if (!header_result) { + return false; // Header doesn't exist, so block doesn't exist + } + + // Header exists - check if we have the full block + auto const heights = database_.internal_db().get_last_heights(); + if (!heights) { + return false; + } + + auto const [header_height, block_height] = *heights; + auto const this_block_height = header_result->second; + + // Block exists only if its height <= block_height + return this_block_height <= block_height; +} + std::expected block_chain::get_branch_work(uint256_t const& maximum, size_t from_height) const { auto const heights = get_last_heights(); if ( ! heights) { return std::unexpected(heights.error()); } - auto const top = heights->first; // header_height + // Use block_height (not header_height) for work comparison + // With headers-first sync, we may have headers without full blocks + auto const top = heights->second; // block_height uint256_t out_work = 0; for (uint32_t height = from_height; height <= top && out_work < maximum; ++height) { diff --git a/src/blockchain/src/pools/block_organizer.cpp b/src/blockchain/src/pools/block_organizer.cpp index cd418fcf..a7d01b7a 100644 --- a/src/blockchain/src/pools/block_organizer.cpp +++ b/src/blockchain/src/pools/block_organizer.cpp @@ -83,7 +83,7 @@ bool block_organizer::stop() { // Organize sequence. //----------------------------------------------------------------------------- -::asio::awaitable block_organizer::organize(block_const_ptr block) { +::asio::awaitable block_organizer::organize(block_const_ptr block, bool headers_pre_validated) { // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_high_priority(); //TODO: is it possible to remove this mutex? @@ -101,7 +101,8 @@ ::asio::awaitable block_organizer::organize(block_const_ptr block) { } // Checks that are independent of chain state. - auto ec = co_await validator_.check(block); + // For headers-first sync, skip header validation since headers were already validated. + auto ec = co_await validator_.check(block, headers_pre_validated); if (stopped()) { mutex_.unlock_high_priority(); @@ -134,7 +135,8 @@ ::asio::awaitable block_organizer::organize(block_const_ptr block) { } // Checks that are dependent on chain state and prevouts. - ec = co_await validator_.accept(branch); + // For headers-first sync, use accept_body() to skip header validation. + ec = co_await validator_.accept(branch, headers_pre_validated); if (stopped()) { mutex_.unlock_high_priority(); diff --git a/src/blockchain/src/pools/header_organizer.cpp b/src/blockchain/src/pools/header_organizer.cpp index 2477980b..af0851fb 100644 --- a/src/blockchain/src/pools/header_organizer.cpp +++ b/src/blockchain/src/pools/header_organizer.cpp @@ -82,9 +82,15 @@ header_organize_result header_organizer::add_headers(domain::message::header::li height, encode_hash(tip_hash_)); for (auto const& header : headers) { - // Validate header + // Compute hash first (needed for validation) + KTH_STATS_TIME_START(hash); + auto const hash = header.hash(); + KTH_STATS_TIME_END(global_sync_stats(), hash, hash_time_ns, hash_calls); + + // Validate header with full chain-state validation + // This includes: PoW check, difficulty, checkpoint, version, MTP KTH_STATS_TIME_START(validate); - auto const ec = validate(header, height, prev_hash); + auto const ec = validate_full(header, hash, height, tip_index_); KTH_STATS_TIME_END(global_sync_stats(), validate, validate_time_ns, validate_calls); if (ec) { @@ -94,11 +100,6 @@ header_organize_result header_organizer::add_headers(domain::message::header::li break; } - // Compute hash and add to index - KTH_STATS_TIME_START(hash); - auto const hash = header.hash(); - KTH_STATS_TIME_END(global_sync_stats(), hash, hash_time_ns, hash_calls); - KTH_STATS_TIME_START(index_add); auto const add_result = index_.add(hash, header); KTH_STATS_TIME_END(global_sync_stats(), index_add, index_add_time_ns, index_add_calls); @@ -123,10 +124,10 @@ header_organize_result header_organizer::add_headers(domain::message::header::li } // Log progress every 1000 headers - if (result.headers_added > 0 && result.headers_added % 1000 == 0) { - spdlog::debug("[header_organizer] Validated {} headers, height {}...", - result.headers_added, height - 1); - } + // if (result.headers_added > 0 && result.headers_added % 1000 == 0) { + // spdlog::debug("[header_organizer] Validated {} headers, height {}...", + // result.headers_added, height - 1); + // } } spdlog::debug("[header_organizer] Validation complete: {} headers added, total size {}", @@ -160,9 +161,22 @@ uint32_t header_organizer::tip_timestamp() const { // Validation // ============================================================================= -code header_organizer::validate(domain::chain::header const& header, int32_t height, - hash_digest const& previous) const { - return validator_.validate(header, static_cast(height), previous); +code header_organizer::validate_full(domain::chain::header const& header, + hash_digest const& hash, + int32_t height, + header_index::index_t parent_idx) const { + // First do context-free check (PoW, timestamp not too far in future) + // Skip PoW check if under checkpoint (trusted headers) + if (!validator_.is_under_checkpoint(size_t(height))) { + auto const ec = validator_.check(header); + if (ec) { + return ec; + } + } + + // Then do full accept validation with chain_state built from header_index + // This validates: difficulty, checkpoint, version, MTP + return validator_.accept_full(header, hash, size_t(height), parent_idx, index_); } } // namespace kth::blockchain diff --git a/src/blockchain/src/populate/populate_chain_state.cpp b/src/blockchain/src/populate/populate_chain_state.cpp index eca77ff9..77d14824 100644 --- a/src/blockchain/src/populate/populate_chain_state.cpp +++ b/src/blockchain/src/populate/populate_chain_state.cpp @@ -36,7 +36,7 @@ populate_chain_state::populate_chain_state(block_chain const& chain, settings co settings_(settings), #endif //KTH_CURRENCY_BCH configured_forks_(settings.enabled_forks()) - , checkpoints_(infrastructure::config::checkpoint::sort(settings.checkpoints)) + , checkpoints_(settings.checkpoints_sorted) , network_(network) , chain_(chain) {} diff --git a/src/blockchain/src/settings.cpp b/src/blockchain/src/settings.cpp index 1d4e5c20..a5dbc056 100644 --- a/src/blockchain/src/settings.cpp +++ b/src/blockchain/src/settings.cpp @@ -70,6 +70,12 @@ settings::settings(domain::config::network net) { } checkpoints = domain::config::default_checkpoints(net); + + // Pre-compute sorted list and max height + checkpoints_sorted = infrastructure::config::checkpoint::sort(checkpoints); + if (!checkpoints_sorted.empty()) { + max_checkpoint_height = checkpoints_sorted.back().height(); + } } uint32_t settings::enabled_forks() const { diff --git a/src/blockchain/src/validate/validate_block.cpp b/src/blockchain/src/validate/validate_block.cpp index 395cbe62..253ae417 100644 --- a/src/blockchain/src/validate/validate_block.cpp +++ b/src/blockchain/src/validate/validate_block.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,7 @@ void validate_block::stop() { //----------------------------------------------------------------------------- // These checks are context free. -::asio::awaitable validate_block::check(block_const_ptr block) const { +::asio::awaitable validate_block::check(block_const_ptr block, bool headers_pre_validated) const { // The block hasn't been checked yet. if (block->transactions().empty()) { co_return error::success; @@ -108,6 +109,11 @@ ::asio::awaitable validate_block::check(block_const_ptr block) const { } // Run context free checks, sets time internally. + // For headers-first sync, skip header validation (PoW, timestamp) since + // headers were already validated during header sync. + if (headers_pre_validated) { + co_return block->check_body(); + } co_return block->check(); } @@ -130,7 +136,7 @@ code validate_block::check_block_bucket(block_const_ptr block, size_t bucket, si //----------------------------------------------------------------------------- // These checks require chain state, and block state if not under checkpoint. -::asio::awaitable validate_block::accept(branch::const_ptr branch) const { +::asio::awaitable validate_block::accept(branch::const_ptr branch, bool headers_pre_validated) const { auto const block = branch->top(); KTH_ASSERT(block); @@ -155,30 +161,39 @@ ::asio::awaitable validate_block::accept(branch::const_ptr branch) const { co_return populate_ec; } - auto const height = block->validation.state->height(); + auto const& state = *block->validation.state; // Run contextual block non-tx checks (sets start time). - auto const error_code = block->accept(false); + // For headers-first sync, skip header validation since headers were + // already validated during header sync. + if ( ! headers_pre_validated) { + // Full validation: validate header first + auto const header_ec = validate_header::accept_header(block->header(), block->hash(), state); + if (header_ec) { + co_return header_ec; + } + } - if (error_code) { - co_return error_code; + // Validate block body (same for both cases) + auto const body_ec = accept_block_body(*block, state); + if (body_ec) { + co_return body_ec; } auto const sigops = std::make_shared(0); - auto const state = block->validation.state; - KTH_ASSERT(state); + #if defined(KTH_CURRENCY_BCH) bool const bip141 = false; #else - auto const bip141 = state->is_enabled(domain::machine::rule_fork::bip141_rule); + auto const bip141 = state.is_enabled(domain::machine::rule_fork::bip141_rule); #endif - if (state->is_under_checkpoint()) { + if (state.is_under_checkpoint()) { co_return error::success; } auto const count = block->transactions().size(); - auto const bip16 = state->is_enabled(domain::machine::rule_fork::bip16_rule); + auto const bip16 = state.is_enabled(domain::machine::rule_fork::bip16_rule); auto const buckets = std::min(threads_, count); KTH_ASSERT(buckets != 0); @@ -404,4 +419,95 @@ void validate_block::dump(code const& ec, transaction const& tx, uint32_t input_ prevout.validation.cache.value(), tx_hash, input_index, encode_base16(tx.to_data(true))); } +// ============================================================================= +// Static validation functions (pure, no side effects) +// These replace the accept/connect methods that were in block_basis. +// ============================================================================= + +code validate_block::accept_block_body( + domain::chain::block const& block, + domain::chain::chain_state const& state) { + + auto const& header = block.header(); + auto const block_size = block.serialized_size(); + + auto const bip16 = state.is_enabled(domain::machine::rule_fork::bip16_rule); + auto const bip34 = state.is_enabled(domain::machine::rule_fork::bip34_rule); + auto const bip113 = state.is_enabled(domain::machine::rule_fork::bip113_rule); + auto const bip141 = false; // No segwit + + // Block size validation +#if defined(KTH_CURRENCY_BCH) + if (state.is_lobachevski_enabled()) { + if (block_size > state.dynamic_max_block_size()) { + return error::block_size_limit; + } + } else if (state.is_pythagoras_enabled()) { + if (block_size > static_max_block_size(state.network())) { + return error::block_size_limit; + } + } else { + if (block_size > max_block_size::mainnet_old) { + return error::block_size_limit; + } + } +#else + if (block_size > max_block_size::mainnet_old) { + return error::block_size_limit; + } +#endif + + // Under checkpoint: Only verify merkle root (done in check_body) + if (state.is_under_checkpoint()) { + return error::success; + } + + // Transaction ordering check +#if defined(KTH_CURRENCY_BCH) + if (state.is_euclid_enabled()) { + if ( ! block.is_canonical_ordered()) { + return error::non_canonical_ordered; + } + } else { + if (block.is_forward_reference()) { + return error::forward_reference; + } + } +#else + if (block.is_forward_reference()) { + return error::forward_reference; + } +#endif + + // Coinbase script height check (BIP34) + if (bip34 && !block.is_valid_coinbase_script(state.height())) { + return error::coinbase_height_mismatch; + } + + // Coinbase claim check + if ( ! block.is_valid_coinbase_claim(state.height())) { + return error::coinbase_value_limit; + } + + // Finality check + auto const block_time = bip113 ? state.median_time_past() : header.timestamp(); + if ( ! block.is_final(state.height(), block_time)) { + return error::block_non_final; + } + + // Sigops check (for non-Fermat BCH or BTC/LTC) +#if defined(KTH_CURRENCY_BCH) + if ( ! state.is_fermat_enabled()) { +#endif + size_t const allowed_sigops = get_allowed_sigops(block_size); + if (block.signature_operations(bip16, bip141) > allowed_sigops) { + return error::block_embedded_sigop_limit; + } +#if defined(KTH_CURRENCY_BCH) + } +#endif + + return error::success; +} + } // namespace kth::blockchain diff --git a/src/blockchain/src/validate/validate_header.cpp b/src/blockchain/src/validate/validate_header.cpp index 2ee02e78..75ecffb4 100644 --- a/src/blockchain/src/validate/validate_header.cpp +++ b/src/blockchain/src/validate/validate_header.cpp @@ -5,9 +5,11 @@ #include #include +#include #include +#include #include #include @@ -17,7 +19,9 @@ using namespace kth::domain::chain; using namespace kth::infrastructure::config; validate_header::validate_header(settings const& settings, domain::config::network network) - : checkpoints_(checkpoint::sort(settings.checkpoints)) + : settings_(settings) + , checkpoints_(settings.checkpoints_sorted) + , configured_forks_(settings.enabled_forks()) , network_(network) , retarget_(network != domain::config::network::regtest) {} @@ -125,4 +129,314 @@ size_t validate_header::last_checkpoint_height() const { return checkpoints_.back().height(); } +// ============================================================================= +// Full validation with header_index +// ============================================================================= + +std::expected validate_header::collect_historical_data( + chain_state::map const& map, + header_index::index_t parent_idx, + header_index const& index) const { + + chain_state::data data{}; + + // Resize all containers + data.bits.ordered.resize(map.bits.count); + data.version.ordered.resize(map.version.count); + data.timestamp.ordered.resize(map.timestamp.count); + + // Calculate maximum steps needed + auto const max_count = std::max({map.bits.count, map.version.count, map.timestamp.count}); + + if (max_count == 0) { + return data; + } + + // Single traversal collecting all data types + auto idx = parent_idx; + for (size_t step = 0; step < max_count && idx != header_index::null_index; ++step) { + // Collect bits if still needed (store in reverse order) + if (step < map.bits.count) { + data.bits.ordered[map.bits.count - 1 - step] = index.get_bits(idx); + } + + // Collect versions if still needed + if (step < map.version.count) { + data.version.ordered[map.version.count - 1 - step] = index.get_version(idx); + } + + // Collect timestamps if still needed + if (step < map.timestamp.count) { + data.timestamp.ordered[map.timestamp.count - 1 - step] = index.get_timestamp(idx); + } + + idx = index.get_parent_index(idx); + } + + // Verify we collected enough data + if (idx == header_index::null_index) { + // Check if we collected all required data + auto const parent_height = index.get_height(parent_idx); + if (parent_height + 1 < static_cast(max_count)) { + spdlog::warn("[validate_header] collect_historical_data: insufficient chain depth, " + "need {} but only have {}", max_count, parent_height + 1); + return std::unexpected(error::operation_failed); + } + } + + // Collect retarget timestamp if needed (separate lookup via skip pointers) + if (map.timestamp_retarget != chain_state::map::unrequested) { + auto const retarget_height = static_cast(map.timestamp_retarget); + auto retarget_idx = index.get_ancestor(parent_idx, retarget_height); + + if (retarget_idx == header_index::null_index) { + spdlog::warn("[validate_header] collect_historical_data: could not find retarget ancestor at height {}", + retarget_height); + return std::unexpected(error::operation_failed); + } + +#if defined(KTH_CURRENCY_LTC) + // Litecoin uses (retarget - 1) for some reason + if (retarget_height > 0) { + retarget_idx = index.get_parent_index(retarget_idx); + } +#endif + data.timestamp.retarget = index.get_timestamp(retarget_idx); + } + + return data; +} + +#if defined(KTH_CURRENCY_BCH) +chain_state::assert_anchor_block_info_t validate_header::get_asert_anchor_block() const { + using namespace kth::domain; + + auto const height = network_map(network_ + , mainnet_asert_anchor_block_height + , testnet_asert_anchor_block_height + , size_t(0) + , testnet4_asert_anchor_block_height + , scalenet_asert_anchor_block_height + , chipnet_asert_anchor_block_height + ); + + auto const ancestor_time = network_map(network_ + , mainnet_asert_anchor_block_ancestor_time + , testnet_asert_anchor_block_ancestor_time + , size_t(0) + , testnet4_asert_anchor_block_ancestor_time + , scalenet_asert_anchor_block_ancestor_time + , chipnet_asert_anchor_block_ancestor_time + ); + + uint32_t const bits = network_map(network_ + , mainnet_asert_anchor_block_bits + , testnet_asert_anchor_block_bits + , size_t(0) + , testnet4_asert_anchor_block_bits + , scalenet_asert_anchor_block_bits + , chipnet_asert_anchor_block_bits + ); + + return {height, ancestor_time, bits}; +} +#endif // KTH_CURRENCY_BCH + +std::expected validate_header::build_chain_state_data( + size_t height, + domain::chain::header const& header, + hash_digest const& hash, + header_index::index_t parent_idx, + header_index const& index) const { + + if (height == 0) { + spdlog::warn("[validate_header] build_chain_state_data: height 0 is not valid"); + return std::unexpected(error::operation_failed); + } + + // Get the map that defines what data we need to collect + auto const map = chain_state::get_map(height, checkpoints_, configured_forks_, network_); + + // Collect historical data from header_index (single traversal) + auto result = collect_historical_data(map, parent_idx, index); + if (!result) { + return std::unexpected(result.error()); + } + + auto& data = *result; + + // Set metadata + data.height = height; + data.hash = hash; + + // Set self values from the header being validated + data.bits.self = header.bits(); + data.version.self = header.version(); + data.timestamp.self = header.timestamp(); + + // Handle collision hash (for duplicate tx hash detection) + if (map.allow_collisions_height != chain_state::map::unrequested) { + auto const collision_idx = index.get_ancestor(parent_idx, static_cast(map.allow_collisions_height)); + data.allow_collisions_hash = (collision_idx != header_index::null_index) + ? index.get_hash(collision_idx) + : null_hash; + } else { + data.allow_collisions_hash = null_hash; + } + +#if ! defined(KTH_CURRENCY_BCH) + // BIP9 bit0/bit1 hashes + if (map.bip9_bit0_height != chain_state::map::unrequested) { + auto const bip9_idx = index.get_ancestor(parent_idx, static_cast(map.bip9_bit0_height)); + data.bip9_bit0_hash = (bip9_idx != header_index::null_index) + ? index.get_hash(bip9_idx) + : null_hash; + } else { + data.bip9_bit0_hash = null_hash; + } + + if (map.bip9_bit1_height != chain_state::map::unrequested) { + auto const bip9_idx = index.get_ancestor(parent_idx, static_cast(map.bip9_bit1_height)); + data.bip9_bit1_hash = (bip9_idx != header_index::null_index) + ? index.get_hash(bip9_idx) + : null_hash; + } else { + data.bip9_bit1_hash = null_hash; + } +#endif + +#if defined(KTH_CURRENCY_BCH) + // ABLA state - we don't have block size during header validation + // Initialize with default values; actual block size validation happens during block sync + data.abla_state = domain::chain::abla::state(settings_.abla_config, static_max_block_size(network_)); +#endif + + return data; +} + +code validate_header::accept_full(domain::chain::header const& header, + hash_digest const& hash, + size_t height, + header_index::index_t parent_idx, + header_index const& index) const { + // Basic chain continuity check + if (parent_idx != header_index::null_index) { + auto const expected_prev = index.get_prev_block_hash(parent_idx); + // parent_idx points to the parent header, so we need to check the parent's hash + auto const parent_hash = index.get_hash(parent_idx); + if (header.previous_block_hash() != parent_hash) { + return error::store_block_missing_parent; + } + } else if (height != 0) { + // Non-genesis block without parent + return error::store_block_missing_parent; + } + + // Build chain_state data from header_index + auto data_result = build_chain_state_data(height, header, hash, parent_idx, index); + if (!data_result) { + spdlog::error("[validate_header] accept_full: failed to build chain_state data for height {}", height); + return data_result.error(); + } + + // Create chain_state from the data +#if defined(KTH_CURRENCY_BCH) + auto const anchor = get_asert_anchor_block(); + chain_state state( + std::move(*data_result), + configured_forks_, + checkpoints_, + network_, + anchor, + settings_.asert_half_life, + settings_.abla_config, + leibniz_t(settings_.leibniz_activation_time), + cantor_t(settings_.cantor_activation_time) + ); +#else + chain_state state( + std::move(*data_result), + configured_forks_, + checkpoints_, + network_ + ); +#endif + + // Now perform the full header validation using chain_state + // This is equivalent to header_basis::accept() + + // 1. Difficulty check + if (header.bits() != state.work_required()) { + spdlog::debug("[validate_header] accept_full: incorrect PoW at height {}: " + "header bits={:#x}, required={:#x}", + height, header.bits(), state.work_required()); + return error::incorrect_proof_of_work; + } + + // 2. Checkpoint conflict check + if (state.is_checkpoint_conflict(hash)) { + return error::checkpoints_failed; + } + + // 3. Under checkpoint - skip remaining checks + if (state.is_under_checkpoint()) { + return error::success; + } + + // 4. Version check + if (header.version() < state.minimum_version()) { + spdlog::debug("[validate_header] accept_full: old version at height {}: " + "header version={}, minimum={}", + height, header.version(), state.minimum_version()); + return error::old_version_block; + } + + // 5. Median time past check + if (header.timestamp() <= state.median_time_past()) { + spdlog::debug("[validate_header] accept_full: timestamp too early at height {}: " + "header timestamp={}, MTP={}", + height, header.timestamp(), state.median_time_past()); + return error::timestamp_too_early; + } + + return error::success; +} + +// ============================================================================= +// Static validation functions (pure, no side effects) +// ============================================================================= + +code validate_header::accept_header( + domain::chain::header const& header, + hash_digest const& hash, + domain::chain::chain_state const& state) { + + // 1. Difficulty check + if (header.bits() != state.work_required()) { + return error::incorrect_proof_of_work; + } + + // 2. Checkpoint conflict check + if (state.is_checkpoint_conflict(hash)) { + return error::checkpoints_failed; + } + + // 3. Under checkpoint - skip remaining checks + if (state.is_under_checkpoint()) { + return error::success; + } + + // 4. Version check + if (header.version() < state.minimum_version()) { + return error::old_version_block; + } + + // 5. Median time past check + if (header.timestamp() <= state.median_time_past()) { + return error::timestamp_too_early; + } + + return error::success; +} + } // namespace kth::blockchain diff --git a/src/blockchain/test/block_index_bench/benchmarks.cpp b/src/blockchain/test/block_index_bench/benchmarks.cpp index 19e54e5b..400fd933 100644 --- a/src/blockchain/test/block_index_bench/benchmarks.cpp +++ b/src/blockchain/test/block_index_bench/benchmarks.cpp @@ -3960,7 +3960,7 @@ void test_soa_traversal_unlock_after_lookup() { for (size_t t = 0; t < num_traversers; ++t) { threads.emplace_back([&store, &cached_indices, &stop, &traverse_count, t, traversal_depth] { std::mt19937 rng(t); - std::uniform_int_distribution dist(static_cast(traversal_depth), cached_indices.size() - 1); + std::uniform_int_distribution dist(size_t(traversal_depth), cached_indices.size() - 1); while (!stop.load(std::memory_order_relaxed)) { // Use CACHED index - no lock, no synchronization with writers! uint32_t start_idx = cached_indices[dist(rng)]; diff --git a/src/consensus/src/bch-rules/coins.h b/src/consensus/src/bch-rules/coins.h index 680c63da..71514e09 100644 --- a/src/consensus/src/bch-rules/coins.h +++ b/src/consensus/src/bch-rules/coins.h @@ -109,7 +109,7 @@ struct hash { } }; } -// return static_cast(SipHashUint256Extra(k0(), k1(), o.GetTxId(), o.GetN())); +// return size_t(SipHashUint256Extra(k0(), k1(), o.GetTxId(), o.GetN())); /** Cursor for iterating over CoinsView state */ class CCoinsViewCursor { diff --git a/src/consensus/src/bch-rules/script/interpreter.cpp b/src/consensus/src/bch-rules/script/interpreter.cpp index 721f8335..a5e128af 100644 --- a/src/consensus/src/bch-rules/script/interpreter.cpp +++ b/src/consensus/src/bch-rules/script/interpreter.cpp @@ -59,7 +59,7 @@ int FindAndDelete(CScript &script, const CScript &b) { opcodetype opcode; do { result.insert(result.end(), pc2, pc); - while (static_cast(end - pc) >= b.size() && + while (size_t(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; diff --git a/src/consensus/src/bch-rules/util/strencodings.h b/src/consensus/src/bch-rules/util/strencodings.h index 17356dd8..1fe1853c 100644 --- a/src/consensus/src/bch-rules/util/strencodings.h +++ b/src/consensus/src/bch-rules/util/strencodings.h @@ -252,7 +252,7 @@ bool ConvertBits(const O &outfn, I it, I end) { constexpr size_t maxv = (size_t{1} << tobits) - 1u; constexpr size_t max_acc = (size_t{1} << (frombits + tobits - 1u)) - 1u; while (it != end) { - acc = ((acc << frombits) | static_cast(*it)) & max_acc; + acc = ((acc << frombits) | size_t(*it)) & max_acc; bits += frombits; while (bits >= tobits) { bits -= tobits; diff --git a/src/consensus/src/btc-rules/script/interpreter.cpp b/src/consensus/src/btc-rules/script/interpreter.cpp index e636de5a..ea566062 100644 --- a/src/consensus/src/btc-rules/script/interpreter.cpp +++ b/src/consensus/src/btc-rules/script/interpreter.cpp @@ -260,7 +260,7 @@ int FindAndDelete(CScript& script, const CScript& b) do { result.insert(result.end(), pc2, pc); - while (static_cast(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) + while (size_t(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = pc + b.size(); ++nFound; diff --git a/src/database/include/kth/database/databases/internal_database.ipp b/src/database/include/kth/database/databases/internal_database.ipp index f9168491..4ff6bd0d 100644 --- a/src/database/include/kth/database/databases/internal_database.ipp +++ b/src/database/include/kth/database/databases/internal_database.ipp @@ -1103,9 +1103,16 @@ template result_code internal_database_basis::push_block(domain::chain::block const& block, uint32_t height, uint32_t median_time_past, bool insert_reorg, KTH_DB_txn* db_txn) { //precondition: block.transactions().size() >= 1 - auto res = push_block_header(block, height, db_txn); - if (res != result_code::success) { - return res; + result_code res = result_code::success; + + // With headers-first sync, header usually already exists. + // Only write header if it doesn't exist (for backward compatibility/edge cases). + auto existing_header = get_header(height, db_txn); + if ( ! existing_header.has_value()) { + res = push_block_header(block, height, db_txn); + if (res != result_code::success) { + return res; + } } auto const& txs = block.transactions(); diff --git a/src/domain/include/kth/domain/chain/block.hpp b/src/domain/include/kth/domain/chain/block.hpp index 23955c39..b16de53c 100644 --- a/src/domain/include/kth/domain/chain/block.hpp +++ b/src/domain/include/kth/domain/chain/block.hpp @@ -144,9 +144,10 @@ struct KD_API block : block_basis { size_t total_inputs(bool with_coinbase = true) const; code check() const; - code accept(bool transactions = true) const; - code accept(chain_state const& state, bool transactions = true) const; - code connect() const; + + /// Check block body only (skip header validation for headers-first sync). + /// Use this when headers have already been validated during header sync. + code check_body() const; // THIS IS FOR LIBRARY USE ONLY, DO NOT CREATE A DEPENDENCY ON IT. mutable validation_t validation{}; diff --git a/src/domain/include/kth/domain/chain/block_basis.hpp b/src/domain/include/kth/domain/chain/block_basis.hpp index 24cf1b5c..eb0ed01a 100644 --- a/src/domain/include/kth/domain/chain/block_basis.hpp +++ b/src/domain/include/kth/domain/chain/block_basis.hpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -159,20 +158,13 @@ struct KD_API block_basis { [[nodiscard]] code check(size_t serialized_size_false) const; + /// Check block body only (skip header validation for headers-first sync). + /// Use this when headers have already been validated during header sync. [[nodiscard]] - code check_transactions() const; - - [[nodiscard]] - code accept(chain_state const& state, size_t serialized_size, bool transactions = true) const; - - [[nodiscard]] - code accept_transactions(chain_state const& state) const; - - [[nodiscard]] - code connect(chain_state const& state) const; + code check_body(size_t serialized_size_false) const; [[nodiscard]] - code connect_transactions(chain_state const& state) const; + code check_transactions() const; // protected: void reset(); diff --git a/src/domain/include/kth/domain/chain/header.hpp b/src/domain/include/kth/domain/chain/header.hpp index a38256aa..b4e4eebd 100644 --- a/src/domain/include/kth/domain/chain/header.hpp +++ b/src/domain/include/kth/domain/chain/header.hpp @@ -106,8 +106,6 @@ struct KD_API header : header_basis, hash_memoizer

{ bool is_valid_proof_of_work(bool retarget = true) const; code check(bool retarget = false) const; - code accept(chain_state const& state) const; - // THIS IS FOR LIBRARY USE ONLY, DO NOT CREATE A DEPENDENCY ON IT. mutable validation_t validation{}; diff --git a/src/domain/include/kth/domain/chain/header_basis.hpp b/src/domain/include/kth/domain/chain/header_basis.hpp index 2a8fef51..e3d19cc1 100644 --- a/src/domain/include/kth/domain/chain/header_basis.hpp +++ b/src/domain/include/kth/domain/chain/header_basis.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -149,9 +148,6 @@ struct KD_API header_basis { [[nodiscard]] code check(hash_digest const& hash, bool retarget = false) const; - [[nodiscard]] - code accept(::kth::domain::chain::chain_state const& state, hash_digest const& hash) const; - void reset(); private: diff --git a/src/domain/include/kth/domain/config/parser.hpp b/src/domain/include/kth/domain/config/parser.hpp index ed40c425..8329d5cc 100644 --- a/src/domain/include/kth/domain/config/parser.hpp +++ b/src/domain/include/kth/domain/config/parser.hpp @@ -215,7 +215,7 @@ kth::infrastructure::config::checkpoint::list default_checkpoints(config::networ checkpoints.emplace_back("0000000017d92f88ed2c81885c57f999184860a042250510be06b3edd12e0dc5", 232000); } else if (network == domain::config::network::mainnet) { - checkpoints.reserve(60); + checkpoints.reserve(64); checkpoints.emplace_back("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 0); checkpoints.emplace_back("0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d", 11'111); checkpoints.emplace_back("000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6", 33'333); @@ -340,6 +340,11 @@ kth::infrastructure::config::checkpoint::list default_checkpoints(config::networ checkpoints.emplace_back("00000000000000000157a0a3dcdc80f1acd809648d238c1e893b26247091b3b4", 898'374); checkpoints.emplace_back("0000000000000000007e2e7dd49323c90d16fd76a521804d709f0d5a442fd42a", 898'375); + checkpoints.emplace_back("000000000000000000ff9445c5039fd67d02e901b3cefe8bd55c1d6afb5fe1cf", 900'000); + checkpoints.emplace_back("000000000000000000a2f9b4d4d79f527a664a9932bb1e3f6016ff66a438c302", 910'000); + checkpoints.emplace_back("0000000000000000016a9d52a9c0a7d7fd3cf1a7cea538565674613a65341186", 920'000); + checkpoints.emplace_back("000000000000000000ee3232281f632df96f4222361d564af0fc2e3da352e34f", 930'000); + // //2026-May Upgrade - leibniz - (1778846400) // checkpoints.emplace_back("", 0); // checkpoints.emplace_back("", 0); diff --git a/src/domain/include/kth/domain/constants/common.hpp b/src/domain/include/kth/domain/constants/common.hpp index 53adc4e4..ebc95755 100644 --- a/src/domain/include/kth/domain/constants/common.hpp +++ b/src/domain/include/kth/domain/constants/common.hpp @@ -8,14 +8,7 @@ #include #include -// #include -// #include - -// #include -// #include -// #include -// #include -// #include +#include namespace kth { diff --git a/src/domain/include/kth/domain/impl/machine/interpreter.ipp b/src/domain/include/kth/domain/impl/machine/interpreter.ipp index 5ed16340..857c1245 100644 --- a/src/domain/include/kth/domain/impl/machine/interpreter.ipp +++ b/src/domain/include/kth/domain/impl/machine/interpreter.ipp @@ -1706,7 +1706,7 @@ interpreter::result interpreter::op_active_bytecode(program& program) { auto const script_end = program.end(); // Calculate the size of the active bytecode - auto const script_size = static_cast(script_end - begin_code_hash); + auto const script_size = size_t(script_end - begin_code_hash); // Check maximum script element size constraint auto const max_script_element_size = program.max_script_element_size(); diff --git a/src/domain/src/chain/block.cpp b/src/domain/src/chain/block.cpp index c7035f0a..64513eed 100644 --- a/src/domain/src/chain/block.cpp +++ b/src/domain/src/chain/block.cpp @@ -340,7 +340,7 @@ size_t block::locator_size(size_t top) { if (remaining < 2) { return top + size_t{1}; } - return first_ten_or_top + static_cast(std::log2(remaining) + 0.5) + size_t{1}; + return first_ten_or_top + size_t(std::log2(remaining) + 0.5) + size_t{1}; } // This algorithm is a network best practice, not a consensus rule. @@ -429,20 +429,10 @@ code block::check() const { return block_basis::check(serialized_size()); } -code block::accept(bool transactions) const { - auto const state = validation.state; - return state ? accept(*state, transactions) : error::operation_failed; -} - -// These checks assume that prevout caching is completed on all tx.inputs. -code block::accept(chain_state const& state, bool transactions) const { - validation.start_accept = asio::steady_clock::now(); - return block_basis::accept(state, serialized_size(), transactions); -} - -code block::connect() const { - auto const state = validation.state; - return state ? block_basis::connect(*state) : error::operation_failed; +// Check block body only (skip header validation for headers-first sync). +code block::check_body() const { + validation.start_check = asio::steady_clock::now(); + return block_basis::check_body(serialized_size()); } } // namespace kth::domain::chain diff --git a/src/domain/src/chain/block_basis.cpp b/src/domain/src/chain/block_basis.cpp index df1d8852..cfbe0ade 100644 --- a/src/domain/src/chain/block_basis.cpp +++ b/src/domain/src/chain/block_basis.cpp @@ -18,14 +18,12 @@ #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -44,7 +42,6 @@ namespace kth::domain::chain { -using namespace kth::domain::machine; using namespace boost::adaptors; // Constructors. @@ -441,26 +438,6 @@ code block_basis::check_transactions() const { return error::success; } -code block_basis::accept_transactions(chain_state const& state) const { - code ec; - for (auto const& tx : transactions_) { - if ( ! tx.validation.validated && (ec = tx.accept(state, false))) { - return ec; - } - } - return error::success; -} - -code block_basis::connect_transactions(chain_state const& state) const { - code ec; - for (auto const& tx : transactions_) { - if ( ! tx.validation.validated && (ec = tx.connect(state))) { - return ec; - } - } - return error::success; -} - // Validation. //----------------------------------------------------------------------------- @@ -470,10 +447,14 @@ code block_basis::check(size_t serialized_size_false) const { if ((ec = header_.check())) { return ec; - - // TODO(legacy): relates to total of tx.size(false) (pool cache). -> no witness size } + return check_body(serialized_size_false); +} + +// Check block body only (skip header validation for headers-first sync). +// Use this when headers have already been validated during header sync. +code block_basis::check_body(size_t serialized_size_false) const { if (serialized_size_false > static_absolute_max_block_size()) { return error::block_size_limit; } @@ -488,132 +469,27 @@ code block_basis::check(size_t serialized_size_false) const { if (is_extra_coinbases()) { return error::extra_coinbases; - // TODO(legacy): determinable from tx pool graph. } #if ! defined(KTH_CURRENCY_BCH) // BTC and LTC - //Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) - // and for BitcoinCash (BCH) before 2018-Nov-15. + // Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) + // and for BitcoinCash (BCH) before 2018-Nov-15. if (is_forward_reference()) { return error::forward_reference; } #endif - - // This is subset of is_internal_double_spend if collisions cannot happen. - ////else if ( ! is_distinct_transaction_set()) - //// return error::internal_duplicate; - - // TODO(legacy): determinable from tx pool graph. if (is_internal_double_spend()) { return error::block_internal_double_spend; - // TODO(legacy): relates height to tx.hash(false) (pool cache). } if ( ! is_valid_merkle_root()) { return error::merkle_mismatch; - - // We cannot know if bip16 is enabled at this point so we disable it. - // This will not make a difference unless prevouts are populated, in which - // case they are ignored. This means that p2sh sigops are not counted here. - // This is a preliminary check, the final count must come from connect(). - // Reenable once sigop caching is implemented, otherwise is deoptimization. - ////else if (signature_operations(false, false) > get_max_block_sigops()) - //// return error::block_legacy_sigop_limit; } return check_transactions(); } -// These checks assume that prevout caching is completed on all tx.inputs. - - -code block_basis::accept(chain_state const& state, size_t serialized_size, bool transactions) const { - auto const bip16 = state.is_enabled(rule_fork::bip16_rule); - auto const bip34 = state.is_enabled(rule_fork::bip34_rule); - auto const bip113 = state.is_enabled(rule_fork::bip113_rule); - auto const bip141 = false; // No segwit - - code ec; - if ((ec = header_.accept(state))) { - return ec; - } - - if (state.is_lobachevski_enabled()) { - if (serialized_size > state.dynamic_max_block_size()) { - return error::block_size_limit; - } - } else if (state.is_pythagoras_enabled()) { - if (serialized_size > static_max_block_size(state.network())) { - return error::block_size_limit; - } - } else { - if (serialized_size > max_block_size::mainnet_old) { - return error::block_size_limit; - } - } - - if (state.is_under_checkpoint()) { - return error::success; - } - - - //Note(kth): LTOR (Legacy Transaction ORdering) is a check just for Bitcoin (BTC) - // and for BitcoinCash (BCH) before 2018-Nov-15. - - if (state.is_euclid_enabled()) { - if ( ! is_canonical_ordered()) { - return error::non_canonical_ordered; - } - } else { - if (is_forward_reference()) { - return error::forward_reference; - } - } - - if (bip34 && !is_valid_coinbase_script(state.height())) { - return error::coinbase_height_mismatch; - } - - // TODO(legacy): relates height to total of tx.fee (pool cach). - if ( ! is_valid_coinbase_claim(state.height())) { - return error::coinbase_value_limit; - } - - // TODO(legacy): relates median time past to tx.locktime (pool cache min tx.time). - auto const block_time = bip113 ? state.median_time_past() : header_.timestamp(); - if ( ! is_final(state.height(), block_time)) { - return error::block_non_final; - } - -#if defined(KTH_CURRENCY_BCH) - if ( ! state.is_fermat_enabled()) { -#endif - // TODO(legacy): determine if performance benefit is worth excluding sigops here. - // TODO(legacy): relates block limit to total of tx.sigops (pool cache tx.sigops). - // This recomputes sigops to include p2sh from prevouts. - size_t const allowed_sigops = get_allowed_sigops(serialized_size); - if (transactions && (signature_operations(bip16, bip141) > allowed_sigops)) { - return error::block_embedded_sigop_limit; - } -#if defined(KTH_CURRENCY_BCH) - } -#endif - - if (transactions) { - return accept_transactions(state); - } - - return ec; -} - -code block_basis::connect(chain_state const& state) const { - if (state.is_under_checkpoint()) { - return error::success; - } - return connect_transactions(state); -} - // Non-member functions. //----------------------------------------------------------------------------- @@ -626,7 +502,7 @@ size_t locator_size(size_t top) { auto const first_ten_or_top = std::min(size_t(10), top); auto const remaining = top - first_ten_or_top; auto const back_off = remaining == 0 ? 0.0 : remaining == 1 ? 1.0 : std::log2(remaining); - auto const rounded_up_log = static_cast(std::nearbyint(back_off)); + auto const rounded_up_log = size_t(std::nearbyint(back_off)); return first_ten_or_top + rounded_up_log + size_t(1); } diff --git a/src/domain/src/chain/chain_state.cpp b/src/domain/src/chain/chain_state.cpp index 87d027a2..2c2da846 100644 --- a/src/domain/src/chain/chain_state.cpp +++ b/src/domain/src/chain/chain_state.cpp @@ -906,7 +906,7 @@ auto timestamps_position(chain_state::timestamps const& times, size_t last_n = m std::vector timestamps_subset(chain_state::timestamps const& times, size_t last_n = median_time_past_interval) { auto at = timestamps_position(times, last_n); - auto n = (std::min)(static_cast(std::distance(at, times.end())), median_time_past_interval); + auto n = (std::min)(size_t(std::distance(at, times.end())), median_time_past_interval); std::vector subset(n); std::copy_n(at, n, subset.begin()); return subset; diff --git a/src/domain/src/chain/header.cpp b/src/domain/src/chain/header.cpp index 753505d8..c34573bb 100644 --- a/src/domain/src/chain/header.cpp +++ b/src/domain/src/chain/header.cpp @@ -148,8 +148,4 @@ code header::check(bool retarget) const { return header_basis::check(hash_pow(), retarget); } -code header::accept(chain_state const& state) const { - return header_basis::accept(state, hash_pow()); -} - } // namespace kth::domain::chain diff --git a/src/domain/src/chain/header_basis.cpp b/src/domain/src/chain/header_basis.cpp index fa3dc672..a2d48151 100644 --- a/src/domain/src/chain/header_basis.cpp +++ b/src/domain/src/chain/header_basis.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -268,28 +267,4 @@ code header_basis::check(hash_digest const& hash, bool retarget) const { return error::success; } -code header_basis::accept(chain_state const& state, hash_digest const& hash) const { - if (bits_ != state.work_required()) { - return error::incorrect_proof_of_work; - } - - if (state.is_checkpoint_conflict(hash)) { - return error::checkpoints_failed; - } - - if (state.is_under_checkpoint()) { - return error::success; - } - - if (version_ < state.minimum_version()) { - return error::old_version_block; - } - - if (timestamp_ <= state.median_time_past()) { - return error::timestamp_too_early; - } - - return error::success; -} - } // namespace kth::domain::chain diff --git a/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp b/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp index 9a5874b3..75e460e3 100644 --- a/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp +++ b/src/infrastructure/include/kth/infrastructure/impl/utility/serializer.ipp @@ -228,7 +228,7 @@ size_t serializer::read_size_big_endian() { // This facilitates safely passing the size into a follow-on writer. // Return zero allows follow-on use before testing reader state. if (size <= max_size_t) { - return static_cast(size); + return size_t(size); } valid_ = false; @@ -259,7 +259,7 @@ size_t serializer::read_size_little_endian() { // This facilitates safely passing the size into a follow-on writer. // Return zero allows follow-on use before testing reader state. if (size <= max_size_t) { - return static_cast(size); + return size_t(size); } valid_ = false; diff --git a/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp b/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp new file mode 100644 index 00000000..5da36b06 --- /dev/null +++ b/src/infrastructure/include/kth/infrastructure/utility/cpu_executor.hpp @@ -0,0 +1,157 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP +#define KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP + +#include +#include +#include +#include + +#include + +namespace kth { + +// ============================================================================= +// CPU Executor (Dedicated Thread Pool for CPU-Bound Work) +// ============================================================================= +// +// A specialized executor for CPU-bound operations that should not block the +// IO thread pool. This separates IO-bound async operations from CPU-intensive +// work like block validation, transaction verification, and cryptographic ops. +// +// Key properties: +// - Separate thread pool from IO operations +// - Sized to match hardware concurrency by default +// - Async interface via awaitable for seamless coroutine integration +// - Work can be posted from any thread +// +// Usage in coroutines: +// cpu_executor cpu; +// +// awaitable validate_block(block_ptr block) { +// // Offload CPU-intensive validation to CPU pool +// bool valid = co_await cpu.execute([&block]() { +// return block->is_valid(); // Runs on CPU pool thread +// }); +// +// if (!valid) { +// throw validation_error("Invalid block"); +// } +// } +// +// Architecture: +// ┌─────────────────┐ ┌─────────────────┐ +// │ IO Thread Pool │ │ CPU Thread Pool │ +// │ (network I/O) │ │ (validation) │ +// │ │ │ │ +// │ peer1.run() │ │ validate() │ +// │ peer2.run() │ ───► │ verify_sig() │ +// │ accept_loop() │ │ hash_block() │ +// │ ... │ │ ... │ +// └─────────────────┘ └─────────────────┘ +// +// ============================================================================= + +class cpu_executor { +public: + // Construct with specified number of threads + // Default: hardware_concurrency (number of CPU cores) + explicit cpu_executor(size_t threads = std::thread::hardware_concurrency()) + : pool_(threads > 0 ? threads : 1) + {} + + // Non-copyable, non-movable + cpu_executor(cpu_executor const&) = delete; + cpu_executor& operator=(cpu_executor const&) = delete; + cpu_executor(cpu_executor&&) = delete; + cpu_executor& operator=(cpu_executor&&) = delete; + + ~cpu_executor() { + stop(); + join(); + } + + // Execute a callable on the CPU pool and return result via awaitable. + // This is the primary interface for offloading CPU work from coroutines. + // + // Example: + // auto result = co_await cpu.execute([]() { + // return expensive_computation(); + // }); + // + template + auto execute(F&& work) -> ::asio::awaitable> { + using result_type = std::invoke_result_t; + + co_return co_await ::asio::co_spawn( + pool_.get_executor(), + [w = std::forward(work)]() -> ::asio::awaitable { + if constexpr (std::is_void_v) { + std::invoke(std::move(w)); + co_return; + } else { + co_return std::invoke(std::move(w)); + } + }, + ::asio::use_awaitable + ); + } + + // Post work to the CPU pool without waiting for result. + // Use when you don't need the result in the calling coroutine. + template + void post(F&& work) { + ::asio::post(pool_.get_executor(), std::forward(work)); + } + + // Get the underlying executor for advanced use cases + [[nodiscard]] + auto get_executor() { + return pool_.get_executor(); + } + + // Stop accepting new work + void stop() { + pool_.stop(); + } + + // Wait for all work to complete + void join() { + pool_.join(); + } + + // Get number of threads in the pool + [[nodiscard]] + size_t thread_count() const noexcept { + return thread_count_; + } + +private: + ::asio::thread_pool pool_; + size_t thread_count_{std::thread::hardware_concurrency()}; +}; + +// ============================================================================= +// Global CPU Executor Access +// ============================================================================= +// +// For convenience, a global CPU executor can be used. However, prefer passing +// the executor explicitly for better testability and control. +// +// Usage: +// auto& cpu = kth::global_cpu_executor(); +// co_await cpu.execute([]() { ... }); +// +// ============================================================================= + +inline cpu_executor& global_cpu_executor() { + static cpu_executor instance; + return instance; +} + +} // namespace kth + +#endif // KTH_INFRASTRUCTURE_CPU_EXECUTOR_HPP diff --git a/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp b/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp index ee927a0c..07d9271a 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/pseudo_random.hpp @@ -74,7 +74,7 @@ struct KI_API pseudo_random { //TODO: replace exceptions with std::expected throw std::runtime_error("getrandom() failed, errno=" + std::to_string(errno)); } - offset += static_cast(ret); + offset += size_t(ret); } #endif } diff --git a/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp index df381ae3..1ad32279 100644 --- a/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp +++ b/src/infrastructure/include/kth/infrastructure/utility/task_group.hpp @@ -7,7 +7,9 @@ #include #include +#include #include +#include #include #include @@ -79,6 +81,10 @@ class task_group { // Spawn a coroutine into the group. // The coroutine will be tracked and join() will wait for it. // Note: This uses ONE internal detached spawn, but the task is tracked. + // + // Accepts either: + // - An awaitable directly: tasks.spawn(some_coro()) + // - A callable returning awaitable: tasks.spawn([&]() -> awaitable { ... }) template void spawn(Coro&& coro) { ++active_count_; @@ -87,7 +93,13 @@ class task_group { ::asio::co_spawn(executor_, [this, c = std::forward(coro)]() mutable -> ::asio::awaitable { try { - co_await std::invoke(std::move(c)); + if constexpr (std::is_invocable_v) { + // It's a callable (lambda, function) - invoke it to get the awaitable + co_await std::invoke(std::move(c)); + } else { + // It's already an awaitable - just await it directly + co_await std::move(c); + } } catch (...) { // TODO: Store exception for later propagation // For now, just decrement and signal diff --git a/src/infrastructure/src/log/sink.cpp b/src/infrastructure/src/log/sink.cpp index 8022fc36..14892309 100644 --- a/src/infrastructure/src/log/sink.cpp +++ b/src/infrastructure/src/log/sink.cpp @@ -11,24 +11,25 @@ namespace kth::log { -void initialize(std::string const& debug_file, std::string const& error_file, bool stdout_enabled, bool verbose) { +void initialize(std::string const& debug_file, [[maybe_unused]] std::string const& error_file, bool stdout_enabled, bool verbose) { try { auto debug_file_sink = std::make_shared(debug_file, true); + // Debug file captures debug+ normally, or trace+ when verbose debug_file_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); - auto error_file_sink = std::make_shared(error_file, true); - error_file_sink->set_level(spdlog::level::err); - if (stdout_enabled) { auto stdout_sink = std::make_shared(); stdout_sink->set_level(verbose ? spdlog::level::trace : spdlog::level::info); - auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink, stdout_sink})); - logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, stdout_sink})); + // Logger level must be trace so all messages reach the debug file sink. + // Each sink filters independently based on its own level. + logger->set_level(spdlog::level::trace); logger->flush_on(spdlog::level::info); spdlog::set_default_logger(logger); } else { - auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink, error_file_sink})); - logger->set_level(verbose ? spdlog::level::trace : spdlog::level::debug); + auto logger = std::make_shared("", spdlog::sinks_init_list({debug_file_sink})); + // Logger level must be trace so all messages reach the debug file sink. + logger->set_level(spdlog::level::trace); logger->flush_on(spdlog::level::debug); spdlog::set_default_logger(logger); } diff --git a/src/infrastructure/src/unicode/unicode_streambuf.cpp b/src/infrastructure/src/unicode/unicode_streambuf.cpp index 12ea7883..98e00331 100644 --- a/src/infrastructure/src/unicode/unicode_streambuf.cpp +++ b/src/infrastructure/src/unicode/unicode_streambuf.cpp @@ -50,7 +50,7 @@ std::streambuf::int_type unicode_streambuf::underflow() { auto const size = static_cast(wide_size_); // Read from the wide input buffer. - auto const read = static_cast(wide_buffer_->sgetn(wide_, size)); + auto const read = size_t(wide_buffer_->sgetn(wide_, size)); // Handle read termination. if (read == 0) { diff --git a/src/infrastructure/src/utility/png.cpp b/src/infrastructure/src/utility/png.cpp index fd996e20..f6a2e756 100644 --- a/src/infrastructure/src/utility/png.cpp +++ b/src/infrastructure/src/utility/png.cpp @@ -23,7 +23,7 @@ bool png::write_png(byte_span data, uint32_t size, std::ostream& out) { extern "C" void sink_write(png_structp png_ptr, png_bytep data, png_size_t length) { static_assert(sizeof(length) <= sizeof(size_t), "png_size_t too large"); - auto const size = static_cast(length); + auto const size = size_t(length); auto& sink = *reinterpret_cast(png_get_io_ptr(png_ptr)); sink.write_bytes(reinterpret_cast(data), size); } diff --git a/src/infrastructure/src/utility/system_memory.cpp b/src/infrastructure/src/utility/system_memory.cpp index 99ed3e31..5d9f64fb 100644 --- a/src/infrastructure/src/utility/system_memory.cpp +++ b/src/infrastructure/src/utility/system_memory.cpp @@ -34,7 +34,7 @@ size_t get_total_system_memory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { - return static_cast(status.ullTotalPhys); + return size_t(status.ullTotalPhys); } return 0; #elif defined(__APPLE__) @@ -42,14 +42,14 @@ size_t get_total_system_memory() { uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctl(mib, 2, &memsize, &len, nullptr, 0) == 0) { - return static_cast(memsize); + return size_t(memsize); } return 0; #elif defined(__FreeBSD__) uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctlbyname("hw.physmem", &memsize, &len, nullptr, 0) == 0) { - return static_cast(memsize); + return size_t(memsize); } return 0; #elif defined(__linux__) @@ -68,7 +68,7 @@ size_t get_available_system_memory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { - return static_cast(status.ullAvailPhys); + return size_t(status.ullAvailPhys); } return 0; #elif defined(__APPLE__) @@ -84,7 +84,7 @@ size_t get_available_system_memory() { // Available = free + inactive + purgeable (can be reclaimed) uint64_t available = (uint64_t)(vm_stats.free_count + vm_stats.inactive_count + vm_stats.purgeable_count) * page_size; - return static_cast(available); + return size_t(available); } return 0; #elif defined(__FreeBSD__) @@ -97,7 +97,7 @@ size_t get_available_system_memory() { unsigned int inactive_count = 0; len = sizeof(inactive_count); sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_count, &len, nullptr, 0); - return static_cast((free_count + inactive_count)) * page_size; + return size_t((free_count + inactive_count)) * page_size; } return 0; #elif defined(__linux__) @@ -109,7 +109,7 @@ size_t get_available_system_memory() { unsigned long long mem_kb; if (sscanf(line, "MemAvailable: %llu kB", &mem_kb) == 1) { fclose(f); - return static_cast(mem_kb * 1024); + return size_t(mem_kb * 1024); } } fclose(f); @@ -143,7 +143,7 @@ size_t get_resident_memory() { #elif defined(_WIN32) PROCESS_MEMORY_COUNTERS pmc; if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { - return static_cast(pmc.WorkingSetSize); + return size_t(pmc.WorkingSetSize); } return 0; #elif defined(__APPLE__) @@ -157,7 +157,7 @@ size_t get_resident_memory() { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage) == 0) { // ru_maxrss is in kilobytes on FreeBSD - return static_cast(usage.ru_maxrss) * 1024; + return size_t(usage.ru_maxrss) * 1024; } return 0; #elif defined(__linux__) diff --git a/src/network/include/kth/network/protocols_coro.hpp b/src/network/include/kth/network/protocols_coro.hpp index a5d6c6d3..f3f7cbee 100644 --- a/src/network/include/kth/network/protocols_coro.hpp +++ b/src/network/include/kth/network/protocols_coro.hpp @@ -298,6 +298,26 @@ KN_API awaitable_expected request_block( hash_digest const& block_hash, std::chrono::seconds timeout); +/// Result of batch block request - block with its height +struct block_with_height { + uint32_t height; + domain::message::block block; +}; + +/// Request multiple blocks in a single getdata (batch mode) +/// Sends ONE getdata with all hashes and receives blocks as they arrive. +/// Much more efficient than requesting blocks one at a time. +/// @param peer The peer session +/// @param blocks Vector of {height, hash} pairs to request +/// @param timeout Maximum time to wait for ALL blocks +/// @return Vector of received blocks with heights, or error +/// @note Blocks may be received out of order; vector is sorted by height on return +[[nodiscard]] +KN_API awaitable_expected> request_blocks_batch( + peer_session& peer, + std::vector> const& blocks, + std::chrono::seconds timeout); + // ----------------------------------------------------------------------------- // Inventory Protocol // ----------------------------------------------------------------------------- diff --git a/src/network/include/kth/network/settings.hpp b/src/network/include/kth/network/settings.hpp index 938f492a..488d8fda 100644 --- a/src/network/include/kth/network/settings.hpp +++ b/src/network/include/kth/network/settings.hpp @@ -42,6 +42,7 @@ struct KN_API settings { uint32_t channel_germination_seconds; uint32_t host_pool_capacity; kth::path hosts_file; + kth::path banlist_file; infrastructure::config::authority self; infrastructure::config::authority::list blacklist; infrastructure::config::endpoint::list peers; diff --git a/src/network/src/banlist.cpp b/src/network/src/banlist.cpp index be002a86..a6bdc984 100644 --- a/src/network/src/banlist.cpp +++ b/src/network/src/banlist.cpp @@ -36,8 +36,25 @@ void banlist::ban( bans_.insert_or_assign(ip, entry); - spdlog::info("[banlist] Banned {} for {}s, reason: {}", - ip.to_string(), duration.count(), to_string(reason)); + // Log with human-readable duration + auto const duration_secs = duration.count(); + if (duration_secs >= 365 * 24 * 60 * 60) { + // More than a year = "permanent" + spdlog::info("[banlist] Banned {} permanently, reason: {}", + ip.to_string(), to_string(reason)); + } else if (duration_secs >= 24 * 60 * 60) { + spdlog::info("[banlist] Banned {} for {} days, reason: {}", + ip.to_string(), duration_secs / (24 * 60 * 60), to_string(reason)); + } else if (duration_secs >= 60 * 60) { + spdlog::info("[banlist] Banned {} for {} hours, reason: {}", + ip.to_string(), duration_secs / (60 * 60), to_string(reason)); + } else { + spdlog::info("[banlist] Banned {} for {}s, reason: {}", + ip.to_string(), duration_secs, to_string(reason)); + } + + // Persist to file immediately (bans are rare, so I/O overhead is acceptable) + save(); } void banlist::ban( @@ -52,6 +69,7 @@ bool banlist::unban(::asio::ip::address const& ip) { auto const erased = bans_.erase(ip); if (erased > 0) { spdlog::info("[banlist] Unbanned {}", ip.to_string()); + save(); // Persist immediately return true; } return false; @@ -94,6 +112,7 @@ size_t banlist::size() const { void banlist::clear() { bans_.clear(); spdlog::info("[banlist] Cleared all bans"); + save(); // Persist immediately } void banlist::sweep_expired() { diff --git a/src/network/src/hosts.cpp b/src/network/src/hosts.cpp index b3c89166..d967df13 100644 --- a/src/network/src/hosts.cpp +++ b/src/network/src/hosts.cpp @@ -32,7 +32,7 @@ inline bool is_ipv4_mapped(infrastructure::message::ip_address const& ip) { } // anonymous namespace hosts::hosts(settings const& settings) - : capacity_(std::min(max_address, static_cast(settings.host_pool_capacity))) + : capacity_(std::min(max_address, size_t(settings.host_pool_capacity))) , disabled_(capacity_ == 0) , file_path_(settings.hosts_file) , addresses_(capacity_ > 0 ? capacity_ : 1) @@ -114,7 +114,7 @@ code hosts::fetch(address& out) const { addresses_.cvisit_all([&](address const& addr) { if (found) return; - if (current == static_cast(random_index)) { + if (current == size_t(random_index)) { out = addr; found = true; } diff --git a/src/network/src/p2p_node.cpp b/src/network/src/p2p_node.cpp index 836f7372..58fe3964 100644 --- a/src/network/src/p2p_node.cpp +++ b/src/network/src/p2p_node.cpp @@ -24,6 +24,7 @@ p2p_node::p2p_node(settings const& settings) , pool_(thread_ceiling(settings.threads)) // 0 means use all cores , manager_(pool_.get_executor()) , hosts_(settings) + , banlist_(settings.banlist_file) , top_block_({null_hash, 0}) , new_peer_channel_(std::make_unique>(pool_.get_executor(), 100)) , stop_signal_(std::make_unique(pool_.get_executor(), 1)) @@ -36,8 +37,11 @@ p2p_node::p2p_node(settings const& settings) } p2p_node::~p2p_node() { + spdlog::debug("[p2p_node] destructor starting"); stop(); + spdlog::debug("[p2p_node] destructor - stop() done, calling join()..."); join(); + spdlog::debug("[p2p_node] destructor done"); } ::asio::awaitable p2p_node::start() { @@ -47,8 +51,14 @@ ::asio::awaitable p2p_node::start() { stopped_ = false; + // Load banlist from file (persisted bans survive restarts) + if (!banlist_.load()) { + spdlog::warn("[p2p_node] Failed to load banlist from file"); + } + // hosts_ loads from file in constructor - spdlog::info("[p2p_node] Loaded {} host addresses", hosts_.count()); + spdlog::info("[p2p_node] Loaded {} host addresses, {} banned IPs", + hosts_.count(), banlist_.size()); // Seed if needed if (hosts_.count() < settings_.host_pool_capacity / 2) { @@ -149,6 +159,9 @@ void p2p_node::stop() { // peer_supervisor's peer_tasks.join() to complete manager_.stop_all(); + // Save banlist to file (final save before shutdown) + banlist_.save(); + // hosts_ saves to file in destructor // NOTE: We do NOT call pool_.stop() here! @@ -700,8 +713,11 @@ ::asio::awaitable p2p_node::run_peer_protocols(peer_session::ptr peer) { // Cleanup spdlog::debug("[p2p_node] Ending protocols for peer [{}]", peer->authority()); + spdlog::debug("[p2p_node] Calling peer->stop() for [{}]", peer->authority()); peer->stop(); + spdlog::debug("[p2p_node] Calling manager_.remove() for [{}]", peer->authority()); co_await manager_.remove(peer); + spdlog::debug("[p2p_node] manager_.remove() completed for [{}]", peer->authority()); } ::asio::awaitable p2p_node::maintain_outbound_connections() { @@ -715,7 +731,7 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { co_await ::asio::post(executor, ::asio::use_awaitable); } - spdlog::debug("[p2p_node] maintain_outbound_connections started"); + spdlog::info("[p2p_node] maintain_outbound_connections started, target: {} peers", settings_.outbound_connections); // Maximum number of parallel connection attempts constexpr size_t max_parallel_attempts = 8; @@ -723,17 +739,26 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { while (!stopped_) { auto const current_count = manager_.count_snapshot(); auto const target = settings_.outbound_connections; + auto const host_count = hosts_.count(); + auto const ban_count = banlist_.size(); if (current_count < target) { // Need more connections auto const needed = target - current_count; + spdlog::debug("[p2p_node] Connections: {}/{}, hosts: {}, banned: {}", + current_count, target, host_count, ban_count); + // Always try max_parallel_attempts to find working peers faster // Many addresses may be stale, so cast a wide net auto const batch_size = max_parallel_attempts; std::vector addresses; addresses.reserve(batch_size); + size_t skipped_banned = 0; + size_t skipped_connected = 0; + size_t skipped_pending = 0; + // Fetch addresses, filtering out duplicates and already-connected IPs for (size_t attempts = 0; attempts < batch_size * 3 && addresses.size() < batch_size && !stopped_; ++attempts) { domain::message::network_address addr; @@ -747,16 +772,19 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { // Skip if already pending connection to this IP if (pending_connections_.contains(ip)) { + ++skipped_pending; continue; } // Skip if already connected to this IP if (co_await manager_.exists_by_ip(ip)) { + ++skipped_connected; continue; } // Skip if banned if (banlist_.is_banned(ip)) { + ++skipped_banned; continue; } @@ -776,7 +804,14 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { } if (addresses.empty()) { - spdlog::debug("[p2p_node] No addresses available for outbound"); + spdlog::warn("[p2p_node] No addresses available (hosts: {}, banned: {}, skipped: {} banned, {} connected, {} pending)", + host_count, ban_count, skipped_banned, skipped_connected, skipped_pending); + + // Re-seed if host pool is too low + if (host_count < settings_.host_pool_capacity / 4) { + spdlog::info("[p2p_node] Host pool low ({}), triggering re-seed...", host_count); + co_await run_seeding(); + } } else { spdlog::debug("[p2p_node] Attempting {} parallel connections (need {}, have {})", addresses.size(), needed, current_count); @@ -818,12 +853,24 @@ ::asio::awaitable p2p_node::maintain_outbound_connections() { } } - // Wait before next check (short interval so shutdown is responsive) - // NOTE: We don't use || with stop_signal_ because the || operator in asio - // waits for BOTH operations to complete, not just the first one. - timer.expires_after(std::chrono::seconds(5)); - co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - // Loop will exit on next iteration if stopped_ is true + // Wait before next check + // Use shorter interval when we're below target to recover faster from bans + // Keep wait_time short to allow quick shutdown response + auto const wait_time = (current_count < target) + ? std::chrono::milliseconds(500) // Fast retry when below target + : std::chrono::seconds(5); // Normal check when at target + + // Log status periodically when at target + if (current_count >= target) { + spdlog::debug("[p2p_node] Connections at target: {}/{}, hosts: {}, banned: {}", + current_count, target, host_count, ban_count); + } + + timer.expires_after(wait_time); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled (shutdown) + } } } @@ -908,10 +955,6 @@ ::asio::awaitable p2p_node::peer_supervisor() { co_return; } - spdlog::info("[p2p_node] Handshake complete with [{}], version {}, {}", - peer->authority(), handshake_result->negotiated_version, - handshake_result->peer_version->user_agent()); - // Add to peer manager auto add_ec = co_await manager_.add(peer); if (add_ec != error::success) { diff --git a/src/network/src/peer_manager.cpp b/src/network/src/peer_manager.cpp index 86f79a17..d51aee49 100644 --- a/src/network/src/peer_manager.cpp +++ b/src/network/src/peer_manager.cpp @@ -92,13 +92,17 @@ ::asio::awaitable peer_manager::remove(peer_session::ptr peer) { co_return; } + spdlog::debug("[peer_manager] remove() called for peer [{}]", peer->authority()); + auto nonce = peer->nonce(); if (nonce == 0) { auto const& auth = peer->authority(); nonce = std::hash{}(auth.to_string()); } + spdlog::debug("[peer_manager] remove() calling remove_by_nonce for peer [{}]", peer->authority()); co_await remove_by_nonce(nonce); + spdlog::debug("[peer_manager] remove() completed for peer [{}]", peer->authority()); } ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { @@ -107,16 +111,23 @@ ::asio::awaitable peer_manager::remove_by_nonce(uint64_t nonce) { // to complete before shutdown finishes, so this operation is safe. // We don't check stopped() because we want cleanup to proceed normally. + spdlog::debug("[peer_manager] remove_by_nonce() starting co_spawn on strand for nonce {}", nonce); + co_await ::asio::co_spawn(strand_, [this, nonce]() -> ::asio::awaitable { + spdlog::debug("[peer_manager] remove_by_nonce() inside strand lambda for nonce {}", nonce); auto it = peers_.find(nonce); if (it != peers_.end()) { spdlog::debug("[peer_manager] Removed peer [{}], remaining: {}", it->second->authority(), peers_.size() - 1); peers_.erase(it); count_.store(peers_.size()); + } else { + spdlog::debug("[peer_manager] Peer with nonce {} not found in map", nonce); } co_return; }, ::asio::use_awaitable); + + spdlog::debug("[peer_manager] remove_by_nonce() co_spawn completed for nonce {}", nonce); } ::asio::awaitable peer_manager::exists_by_nonce(uint64_t nonce) const { diff --git a/src/network/src/peer_session.cpp b/src/network/src/peer_session.cpp index 44439cb8..db55e1ca 100644 --- a/src/network/src/peer_session.cpp +++ b/src/network/src/peer_session.cpp @@ -567,82 +567,98 @@ awaitable_expected async_connect( { using namespace ::asio::experimental::awaitable_operators; - // Create resolver - auto resolver = std::make_shared<::asio::ip::tcp::resolver>(executor); - - // DNS resolution timeout (5 seconds should be plenty for DNS) - auto dns_timer = std::make_shared<::asio::steady_timer>(executor); - dns_timer->expires_after(std::chrono::seconds(5)); - - auto start_time = std::chrono::steady_clock::now(); - spdlog::debug("[async_connect] Starting DNS resolution for {} with 5s timeout", hostname); - - // Use a channel to get the first result (DNS or timeout) - auto result_channel = std::make_shared, - std::error_code - > - >>(executor, 1); - - // Spawn DNS resolution - ::asio::co_spawn(executor, [resolver, hostname, port, result_channel]() -> ::asio::awaitable { - auto [ec, endpoints] = co_await resolver->async_resolve( - hostname, std::to_string(port), ::asio::as_tuple(::asio::use_awaitable)); - result_channel->try_send(std::error_code{}, - std::variant, std::error_code>{ - std::make_tuple(ec, endpoints)}); - }, ::asio::detached); - - // Spawn timer - ::asio::co_spawn(executor, [dns_timer, result_channel]() -> ::asio::awaitable { - auto [ec] = co_await dns_timer->async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (!ec) { + // Try to parse hostname as IP address first (skip DNS for IPs) + std::error_code ip_parse_ec; + auto ip_address = ::asio::ip::make_address(hostname, ip_parse_ec); + + ::asio::ip::tcp::endpoint direct_endpoint; + bool is_ip_address = !ip_parse_ec; + + if (is_ip_address) { + // Hostname is already an IP address, skip DNS resolution + direct_endpoint = ::asio::ip::tcp::endpoint(ip_address, port); + spdlog::debug("[async_connect] {} is an IP address, skipping DNS", hostname); + } else { + // Need DNS resolution + auto resolver = std::make_shared<::asio::ip::tcp::resolver>(executor); + + // DNS resolution timeout (5 seconds should be plenty for DNS) + auto dns_timer = std::make_shared<::asio::steady_timer>(executor); + dns_timer->expires_after(std::chrono::seconds(5)); + + auto start_time = std::chrono::steady_clock::now(); + spdlog::debug("[async_connect] Starting DNS resolution for {} with 5s timeout", hostname); + + // Use a channel to get the first result (DNS or timeout) + auto result_channel = std::make_shared, + std::error_code + > + >>(executor, 1); + + // Spawn DNS resolution + ::asio::co_spawn(executor, [resolver, hostname, port, result_channel]() -> ::asio::awaitable { + auto [ec, endpoints] = co_await resolver->async_resolve( + hostname, std::to_string(port), ::asio::as_tuple(::asio::use_awaitable)); result_channel->try_send(std::error_code{}, std::variant, std::error_code>{ - std::make_error_code(std::errc::timed_out)}); - } - }, ::asio::detached); + std::make_tuple(ec, endpoints)}); + }, ::asio::detached); + + // Spawn timer + ::asio::co_spawn(executor, [dns_timer, result_channel]() -> ::asio::awaitable { + auto [ec] = co_await dns_timer->async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (!ec) { + result_channel->try_send(std::error_code{}, + std::variant, std::error_code>{ + std::make_error_code(std::errc::timed_out)}); + } + }, ::asio::detached); - // Wait for first result - auto [recv_ec, result] = co_await result_channel->async_receive( - ::asio::as_tuple(::asio::use_awaitable)); + // Wait for first result + auto [recv_ec, result] = co_await result_channel->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); - auto elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start_time).count(); + auto elapsed = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start_time).count(); - // Cancel whichever didn't complete - resolver->cancel(); - dns_timer->cancel(); + // Cancel whichever didn't complete + resolver->cancel(); + dns_timer->cancel(); - if (recv_ec) { - spdlog::debug("[async_connect] DNS channel error for {}: {}", hostname, recv_ec.message()); - co_return std::unexpected(error::resolve_failed); - } + if (recv_ec) { + spdlog::debug("[async_connect] DNS channel error for {}: {}", hostname, recv_ec.message()); + co_return std::unexpected(error::resolve_failed); + } - // Check which result we got - if (result.index() == 1) { - // Timeout - spdlog::debug("[async_connect] DNS resolution for {} timed out after {}ms", hostname, elapsed); - co_return std::unexpected(error::resolve_failed); - } + // Check which result we got + if (result.index() == 1) { + // Timeout + spdlog::debug("[async_connect] DNS resolution for {} timed out after {}ms", hostname, elapsed); + co_return std::unexpected(error::resolve_failed); + } - auto [resolve_ec, endpoints] = std::get<0>(result); - spdlog::debug("[async_connect] DNS completed for {} in {}ms, ec={}", hostname, elapsed, resolve_ec.message()); + auto [resolve_ec, endpoints] = std::get<0>(result); + spdlog::debug("[async_connect] DNS completed for {} in {}ms, ec={}", hostname, elapsed, resolve_ec.message()); + + if (resolve_ec) { + spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); + co_return std::unexpected(error::resolve_failed); + } - if (resolve_ec) { - spdlog::debug("[async_connect] Failed to resolve {}: {}", hostname, resolve_ec.message()); - co_return std::unexpected(error::resolve_failed); + // Use first resolved endpoint + direct_endpoint = *endpoints.begin(); } - // Create socket and timer for timeout + // Create socket and timer for connection timeout ::asio::ip::tcp::socket socket(executor); ::asio::steady_timer timer(executor); timer.expires_after(timeout); - // Race: connect vs timeout + // Race: connect vs timeout (use single endpoint connect) auto connect_result = co_await ( - ::asio::async_connect(socket, endpoints, ::asio::as_tuple(::asio::use_awaitable)) || + socket.async_connect(direct_endpoint, ::asio::as_tuple(::asio::use_awaitable)) || timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) ); @@ -652,7 +668,7 @@ awaitable_expected async_connect( co_return std::unexpected(error::channel_timeout); } - auto [connect_ec, endpoint] = std::get<0>(connect_result); + auto [connect_ec] = std::get<0>(connect_result); if (connect_ec) { spdlog::debug("[async_connect] Failed to connect to {}:{}: {}", hostname, port, connect_ec.message()); diff --git a/src/network/src/protocols_coro.cpp b/src/network/src/protocols_coro.cpp index fed1555b..c852c14a 100644 --- a/src/network/src/protocols_coro.cpp +++ b/src/network/src/protocols_coro.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include @@ -668,6 +670,108 @@ awaitable_expected request_block( } } +awaitable_expected> request_blocks_batch( + peer_session& peer, + std::vector> const& blocks, + std::chrono::seconds timeout) +{ + if (blocks.empty()) { + co_return std::vector{}; + } + + // Build hash -> height lookup map + boost::unordered_flat_map expected_blocks; + expected_blocks.reserve(blocks.size()); + + // Build inventory list for getdata + domain::message::inventory_vector::list inventories; + inventories.reserve(blocks.size()); + + for (auto const& [height, hash] : blocks) { + expected_blocks[hash] = height; + inventories.emplace_back(domain::message::inventory_vector::type_id::block, hash); + } + + domain::message::get_data request(std::move(inventories)); + + spdlog::debug("[protocol] Requesting {} blocks in batch from [{}] ({}-{})", + blocks.size(), peer.authority(), + blocks.front().first, blocks.back().first); + + // Send ONE getdata with all block hashes + auto ec = co_await peer.send(request); + if (ec != error::success) { + co_return std::unexpected(ec); + } + + // Receive blocks as they arrive + auto executor = co_await ::asio::this_coro::executor; + auto deadline = std::chrono::steady_clock::now() + timeout; + + std::vector received_blocks; + received_blocks.reserve(blocks.size()); + + while (received_blocks.size() < blocks.size()) { + auto remaining = std::chrono::duration_cast( + deadline - std::chrono::steady_clock::now()); + + if (remaining <= 0s) { + spdlog::debug("[protocol] Timeout waiting for batch blocks from [{}] ({}/{} received)", + peer.authority(), received_blocks.size(), blocks.size()); + co_return std::unexpected(error::channel_timeout); + } + + ::asio::steady_timer timer(executor, remaining); + + auto result = co_await ( + peer.block_responses().async_receive(::asio::as_tuple(::asio::use_awaitable)) || + timer.async_wait(::asio::as_tuple(::asio::use_awaitable)) + ); + + if (result.index() == 1) { + spdlog::debug("[protocol] Timeout waiting for batch blocks from [{}]", peer.authority()); + co_return std::unexpected(error::channel_timeout); + } + + auto& [recv_ec, raw] = std::get<0>(result); + if (recv_ec) { + co_return std::unexpected(error::channel_stopped); + } + + // Parse the block + byte_reader reader(raw.payload); + auto block_result = domain::message::block::from_data(reader, peer.negotiated_version()); + if (!block_result) { + spdlog::debug("[protocol] Failed to parse block from [{}]", peer.authority()); + co_return std::unexpected(error::bad_stream); + } + + // Look up the height for this block + auto const block_hash = block_result->header().hash(); + auto it = expected_blocks.find(block_hash); + if (it == expected_blocks.end()) { + // Not a block we requested - ignore (could be from another request) + spdlog::trace("[protocol] Received unexpected block from [{}], ignoring", + peer.authority()); + continue; + } + + auto height = it->second; + expected_blocks.erase(it); + + received_blocks.push_back({height, std::move(*block_result)}); + } + + // Sort by height for caller convenience + std::sort(received_blocks.begin(), received_blocks.end(), + [](auto const& a, auto const& b) { return a.height < b.height; }); + + spdlog::debug("[protocol] Received {} blocks in batch from [{}]", + received_blocks.size(), peer.authority()); + + co_return received_blocks; +} + // ----------------------------------------------------------------------------- // Inventory Protocol // ----------------------------------------------------------------------------- diff --git a/src/network/src/settings.cpp b/src/network/src/settings.cpp index 9864f078..0c757f41 100644 --- a/src/network/src/settings.cpp +++ b/src/network/src/settings.cpp @@ -37,6 +37,7 @@ settings::settings() , channel_germination_seconds(30) , host_pool_capacity(1000) , hosts_file("hosts.cache") + , banlist_file("banlist.dat") , self(unspecified_network_address) // , bitcoin_cash(false) diff --git a/src/node-exe/src/main.cpp b/src/node-exe/src/main.cpp index 949f99a8..a9979a17 100644 --- a/src/node-exe/src/main.cpp +++ b/src/node-exe/src/main.cpp @@ -48,8 +48,8 @@ namespace { std::atomic g_signal_received{0}; extern "C" void log_mode_signal_handler(int signal_number) { - std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); - std::fflush(stderr); + // std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); + // std::fflush(stderr); g_signal_received.store(signal_number); } } diff --git a/src/node/CMakeLists.txt b/src/node/CMakeLists.txt index 9e82fdc2..cd2e6f1e 100644 --- a/src/node/CMakeLists.txt +++ b/src/node/CMakeLists.txt @@ -153,6 +153,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") src/utility/reservation.cpp src/utility/reservations.cpp + src/block_download_coordinator.cpp + src/parallel_sync.cpp + src/block_download_coordinator_v2.cpp + src/parallel_sync_v2.cpp ) endif() @@ -184,6 +188,10 @@ set(kth_headers include/kth/node/full_node.hpp include/kth/node/sync_session.hpp include/kth/node/parser.hpp + include/kth/node/block_download_coordinator.hpp + include/kth/node/parallel_sync.hpp + include/kth/node/block_download_coordinator_v2.hpp + include/kth/node/parallel_sync_v2.hpp ) add_library(${PROJECT_NAME} ${MODE} ${kth_sources} ${kth_headers}) diff --git a/src/node/data/bn.cfg b/src/node/data/bn.cfg index 6d4d8a88..c8f55735 100644 --- a/src/node/data/bn.cfg +++ b/src/node/data/bn.cfg @@ -39,8 +39,8 @@ validate_checksum = false inbound_port = 8333 # The target number of incoming network connections, defaults to 0. inbound_connections = 0 -# The target number of outgoing network connections, defaults to 2. -outbound_connections = 2 +# The target number of outgoing network connections, defaults to 8. +outbound_connections = 8 # The attempt limit for manual connection establishment, defaults to 0 (forever). manual_attempt_limit = 0 # The number of concurrent attempts to establish one connection, defaults to 5. diff --git a/src/node/include/kth/node.hpp b/src/node/include/kth/node.hpp index e3494c1a..098adff4 100644 --- a/src/node/include/kth/node.hpp +++ b/src/node/include/kth/node.hpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include diff --git a/src/node/include/kth/node/block_download_coordinator.hpp b/src/node/include/kth/node/block_download_coordinator.hpp new file mode 100644 index 00000000..a8c6e58f --- /dev/null +++ b/src/node/include/kth/node/block_download_coordinator.hpp @@ -0,0 +1,235 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP +#define KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP + +// ============================================================================= +// Block Download Coordinator - Parallel Block Download Management +// ============================================================================= +// +// This class coordinates parallel block downloads across multiple peers: +// +// DESIGN: +// ------- +// - Central coordinator assigns block heights to peers +// - Each peer can have up to MAX_BLOCKS_PER_PEER blocks in-flight +// - Blocks may arrive out-of-order; buffered until ready for validation +// - Validation happens in-order via a separate pipeline +// +// FLOW: +// ----- +// 1. Peer calls claim_blocks() to get next blocks to download +// 2. Peer sends getdata for claimed blocks +// 3. Peer receives blocks and calls block_received() +// 4. Coordinator buffers out-of-order blocks +// 5. Validation pipeline consumes blocks in order +// +// RECOVERY: +// --------- +// - On peer disconnect: reassign its in-flight blocks +// - On timeout: reassign stalled blocks to other peers +// - On validation failure: stop sync and report error +// +// ============================================================================= + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace kth::node { + +/// Configuration for parallel block download +struct parallel_download_config { + /// Maximum blocks in-flight per peer (BCHN: 16) + size_t max_blocks_per_peer{16}; + + /// Global download window - max blocks ahead of validation + size_t global_window{1024}; + + /// Timeout for individual block download + std::chrono::seconds block_timeout{60}; + + /// Timeout before reassigning stalled blocks + std::chrono::seconds stall_timeout{10}; + + /// How often to check for stalled downloads + std::chrono::seconds timeout_check_interval{1}; +}; + +/// Block download coordinator - manages parallel downloads across peers +class KND_API block_download_coordinator { +public: + using block_const_ptr = domain::message::block::const_ptr; + using peer_ptr = network::peer_session::ptr; + + /// Construct coordinator for a block range + /// @param chain Blockchain for validation + /// @param organizer Header organizer (has the header index) + /// @param start_height First block to download (usually 1 for IBD) + /// @param target_height Last block to download + /// @param executor Executor for internal channel + /// @param config Download configuration + block_download_coordinator( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config const& config = {}); + + ~block_download_coordinator(); + + // Non-copyable + block_download_coordinator(block_download_coordinator const&) = delete; + block_download_coordinator& operator=(block_download_coordinator const&) = delete; + + // ------------------------------------------------------------------------- + // Peer Interface + // ------------------------------------------------------------------------- + + /// Claim blocks for a peer to download + /// @param peer The peer claiming blocks + /// @param max_count Maximum blocks to claim (typically 16) + /// @return Vector of {height, hash} pairs to download, empty if none available + [[nodiscard]] + ::asio::awaitable>> claim_blocks( + peer_ptr const& peer, + size_t max_count); + + /// Report that a block was received + /// @param height Block height + /// @param hash Block hash + /// @param block The received block + ::asio::awaitable block_received( + uint32_t height, + hash_digest const& hash, + block_const_ptr block); + + /// Report that a peer disconnected - reassign its blocks + ::asio::awaitable peer_disconnected(peer_ptr const& peer); + + // ------------------------------------------------------------------------- + // Validation Pipeline + // ------------------------------------------------------------------------- + + /// Get next block ready for validation (in-order) + /// Blocks until a block is available or sync is complete/failed + /// @return Block to validate, or nullopt if sync complete/failed + [[nodiscard]] + ::asio::awaitable>> next_block_to_validate(); + + /// Report validation result + void validation_complete(uint32_t height, code result); + + // ------------------------------------------------------------------------- + // Status & Control + // ------------------------------------------------------------------------- + + /// Check for stalled downloads and reassign + void check_timeouts(); + + /// Check if all blocks have been downloaded and validated + [[nodiscard]] + bool is_complete() const; + + /// Check if sync has failed + [[nodiscard]] + bool has_failed() const; + + /// Check if coordinator was stopped externally + [[nodiscard]] + bool is_stopped() const; + + /// Get failure error code + [[nodiscard]] + code failure_reason() const; + + /// Stop the coordinator (cancel pending operations) + void stop(); + + /// Get current progress + struct progress { + uint32_t blocks_downloaded; + uint32_t blocks_validated; + uint32_t blocks_in_flight; + uint32_t blocks_pending; // Downloaded but not yet validated + uint32_t active_peers; // Peers with blocks in-flight + uint32_t start_height; + uint32_t target_height; + std::chrono::steady_clock::time_point start_time; + }; + + [[nodiscard]] + progress get_progress() const; + +private: + // Get hash for a block height from header organizer + hash_digest get_block_hash(uint32_t height) const; + + // Try to push ready blocks to validation channel + void flush_pending_to_validation(); + + // Mark sync as failed + void set_failed(code reason); + + // Configuration + parallel_download_config config_; + + // Blockchain access + blockchain::block_chain& chain_; + blockchain::header_organizer& organizer_; + + // Range to download + uint32_t const start_height_; + uint32_t const target_height_; + + // Strand for serializing access to shared state (replaces mutex) + // All peer operations (claim_blocks, block_received, etc.) run on this strand + ::asio::strand<::asio::any_io_executor> strand_; + std::atomic stopped_{false}; + std::atomic failed_{false}; + code failure_reason_{error::success}; + + // Assignment state + uint32_t next_height_to_assign_; // Next height to assign to a peer + + // In-flight tracking: height -> {peer, request_time} + struct assignment { + peer_ptr peer; + std::chrono::steady_clock::time_point requested_at; + }; + boost::unordered_flat_map in_flight_; + + // Out-of-order buffer: height -> block + boost::unordered_flat_map pending_blocks_; + + // Validation state + uint32_t next_height_to_validate_; + std::atomic blocks_validated_{0}; + + // Timing + std::chrono::steady_clock::time_point start_time_; + + // Channel for validation pipeline + using validation_channel = ::asio::experimental::concurrent_channel< + void(std::error_code, std::pair)>; + std::unique_ptr validation_queue_; +}; + +} // namespace kth::node + +#endif // KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_HPP diff --git a/src/node/include/kth/node/block_download_coordinator_v2.hpp b/src/node/include/kth/node/block_download_coordinator_v2.hpp new file mode 100644 index 00000000..1e3fc839 --- /dev/null +++ b/src/node/include/kth/node/block_download_coordinator_v2.hpp @@ -0,0 +1,238 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP +#define KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP + +// ============================================================================= +// Block Download Coordinator V2 - Lock-Free Parallel Block Download +// ============================================================================= +// +// Simplified coordinator using atomic operations instead of mutex/strand. +// +// DESIGN: +// ------- +// - Uses a slot-based system where each slot represents a chunk of 16 blocks +// - Slots have 3 states: FREE (0), IN_PROGRESS (1), COMPLETED (2) +// - Claim operation is lock-free using CAS +// - Timeout checker can reset stalled slots back to FREE +// - When all slots in a round are COMPLETED, advance to next round +// +// FLOW: +// ----- +// 1. Peer calls claim_chunk() to get a chunk_id +// 2. Peer calculates block range: [start + chunk_id*16, start + chunk_id*16 + 15] +// 3. Peer fetches hashes from header_index and downloads blocks +// 4. Peer calls chunk_completed(chunk_id) when done +// 5. Timeout checker periodically resets stalled IN_PROGRESS slots +// +// ============================================================================= + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace kth::node { + +/// Configuration for parallel block download v2 +struct parallel_download_config_v2 { + /// Blocks per chunk (matches Bitcoin protocol limit) + size_t chunk_size{16}; + + /// Slots per round = max_peers * multiplier + /// Higher = less frequent round resets + size_t slots_multiplier{100}; + + /// Maximum peers expected + size_t max_peers{8}; + + /// Timeout before a slot is considered stalled + std::chrono::seconds stall_timeout{30}; + + /// How often to check for stalled downloads + std::chrono::seconds timeout_check_interval{5}; +}; + +/// Lock-free block download coordinator +class KND_API block_download_coordinator_v2 { +public: + using block_const_ptr = domain::message::block::const_ptr; + + /// Slot states + enum SlotState : uint8_t { + FREE = 0, // Available for assignment + IN_PROGRESS = 1, // Assigned, waiting for completion + COMPLETED = 2 // Blocks received successfully + }; + + /// Construct coordinator for a block range + block_download_coordinator_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config_v2 const& config = {}); + + ~block_download_coordinator_v2(); + + // Non-copyable + block_download_coordinator_v2(block_download_coordinator_v2 const&) = delete; + block_download_coordinator_v2& operator=(block_download_coordinator_v2 const&) = delete; + + // ------------------------------------------------------------------------- + // Peer Interface (Lock-Free) + // ------------------------------------------------------------------------- + + /// Claim a chunk to download + /// @return chunk_id, or nullopt if sync complete + [[nodiscard]] + std::optional claim_chunk(); + + /// Get block range for a chunk + /// @return {start_height, end_height} for the chunk + [[nodiscard]] + std::pair chunk_range(uint32_t chunk_id) const; + + /// Get block hash for a height (from header index) + [[nodiscard]] + hash_digest get_block_hash(uint32_t height) const; + + /// Report that a chunk was completed successfully + void chunk_completed(uint32_t chunk_id); + + /// Report that a chunk failed (will be retried) + void chunk_failed(uint32_t chunk_id); + + // ------------------------------------------------------------------------- + // Block Reception & Validation + // ------------------------------------------------------------------------- + + /// Report a received block for validation pipeline + void block_received(uint32_t height, block_const_ptr block); + + /// Get next block ready for validation (in-order) + [[nodiscard]] + ::asio::awaitable>> next_block_to_validate(); + + /// Report validation result + void validation_complete(uint32_t height, code result); + + // ------------------------------------------------------------------------- + // Status & Control + // ------------------------------------------------------------------------- + + /// Check for stalled downloads and reset them + void check_timeouts(); + + /// Check if all blocks have been validated + [[nodiscard]] + bool is_complete() const; + + /// Check if sync has failed + [[nodiscard]] + bool has_failed() const; + + /// Check if coordinator was stopped + [[nodiscard]] + bool is_stopped() const; + + /// Get failure reason + [[nodiscard]] + code failure_reason() const; + + /// Stop the coordinator + void stop(); + + /// Progress information + struct progress { + uint32_t chunks_assigned; + uint32_t chunks_completed; + uint32_t chunks_in_progress; + uint32_t blocks_validated; + uint32_t blocks_pending; + uint32_t current_round; + uint32_t start_height; + uint32_t target_height; + uint32_t active_peers; + std::chrono::steady_clock::time_point start_time; + }; + + /// Register/unregister active download peers + void peer_started(); + void peer_stopped(); + + [[nodiscard]] + progress get_progress() const; + +private: + /// Try to advance to next round if all slots completed + void try_advance_round(); + + /// Flush pending blocks to validation channel + void flush_pending_to_validation(); + + /// Set sync as failed + void set_failed(code reason); + + /// Get current time in milliseconds + static uint64_t now_ms(); + + // Configuration + parallel_download_config_v2 config_; + size_t slots_per_round_; + + // Blockchain access + blockchain::block_chain& chain_; + blockchain::header_organizer& organizer_; + + // Range to download + uint32_t const start_height_; + uint32_t const target_height_; + uint32_t const total_chunks_; + + // ========================================================================= + // Lock-free slot management + // ========================================================================= + std::atomic round_{0}; + std::vector> slots_; + std::vector> slot_times_; // timestamp when assigned + std::atomic resetting_{false}; + + // Status + std::atomic stopped_{false}; + std::atomic failed_{false}; + code failure_reason_{error::success}; + std::atomic chunks_completed_{0}; + std::atomic blocks_validated_{0}; + std::atomic active_peers_{0}; + + // Validation pipeline - needs synchronization for out-of-order blocks + std::mutex validation_mutex_; + uint32_t next_height_to_validate_; + boost::unordered_flat_map pending_blocks_; + + // Timing + std::chrono::steady_clock::time_point start_time_; + + // Channel for validation pipeline + using validation_channel = ::asio::experimental::concurrent_channel< + void(std::error_code, std::pair)>; + std::unique_ptr validation_queue_; +}; + +} // namespace kth::node + +#endif // KTH_NODE_BLOCK_DOWNLOAD_COORDINATOR_V2_HPP diff --git a/src/node/include/kth/node/executor/executor.hpp b/src/node/include/kth/node/executor/executor.hpp index f5a50f8d..a4b272bc 100644 --- a/src/node/include/kth/node/executor/executor.hpp +++ b/src/node/include/kth/node/executor/executor.hpp @@ -142,6 +142,10 @@ class executor { std::mutex start_mutex_; std::condition_variable start_cv_; code start_result_{error::success}; + + // Tracks when run() coroutine completes (for safe shutdown) + std::promise run_completed_promise_; + std::future run_completed_future_; }; } // namespace kth::node diff --git a/src/node/include/kth/node/parallel_sync.hpp b/src/node/include/kth/node/parallel_sync.hpp new file mode 100644 index 00000000..dc138f3b --- /dev/null +++ b/src/node/include/kth/node/parallel_sync.hpp @@ -0,0 +1,44 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_PARALLEL_SYNC_HPP +#define KTH_NODE_PARALLEL_SYNC_HPP + +#include +#include +#include +#include +#include + +#include + +namespace kth::node { + +/// Result of parallel block sync +struct parallel_sync_result { + code error; + uint32_t blocks_downloaded{0}; + uint32_t blocks_validated{0}; + uint32_t final_height{0}; +}; + +/// Download and validate blocks in parallel from multiple peers +/// @param chain Blockchain for validation +/// @param organizer Header organizer (contains header index) +/// @param network P2P network for peer access +/// @param start_height First block to download +/// @param target_height Last block to download +/// @param config Download configuration +[[nodiscard]] +KND_API ::asio::awaitable parallel_block_sync( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config const& config = {}); + +} // namespace kth::node + +#endif // KTH_NODE_PARALLEL_SYNC_HPP diff --git a/src/node/include/kth/node/parallel_sync_v2.hpp b/src/node/include/kth/node/parallel_sync_v2.hpp new file mode 100644 index 00000000..0828305f --- /dev/null +++ b/src/node/include/kth/node/parallel_sync_v2.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_NODE_PARALLEL_SYNC_V2_HPP +#define KTH_NODE_PARALLEL_SYNC_V2_HPP + +#include + +#include +#include +#include +#include + +namespace kth::node { + +/// Result of parallel block sync v2 +struct parallel_sync_result_v2 { + code error{error::success}; + uint32_t blocks_downloaded{0}; + uint32_t blocks_validated{0}; + uint32_t final_height{0}; +}; + +/// Parallel block sync using lock-free coordinator v2 +/// Downloads blocks from multiple peers in parallel and validates in order +[[nodiscard]] +KND_API +::asio::awaitable parallel_block_sync_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config_v2 const& config = {}); + +} // namespace kth::node + +#endif // KTH_NODE_PARALLEL_SYNC_V2_HPP diff --git a/src/node/include/kth/node/sync_session.hpp b/src/node/include/kth/node/sync_session.hpp index 3db6f8f0..13a58abf 100644 --- a/src/node/include/kth/node/sync_session.hpp +++ b/src/node/include/kth/node/sync_session.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include @@ -86,9 +87,9 @@ struct sync_config { /// If peer doesn't respond with better chain after this, disconnect std::chrono::seconds headers_response_timeout{2 * 60}; - /// Block stalling timeout (BCHN: 2 seconds) - /// If block download window can't move for this long, disconnect - std::chrono::seconds block_stalling_timeout{2}; + /// Block stalling timeout (BCHN: 10 seconds for individual blocks) + /// If a block request hasn't completed in this time, reassign to another peer + std::chrono::seconds block_stalling_timeout{10}; /// Block download timeout base, in units of block interval (BCHN: 10 min equivalent) /// Actual timeout = block_interval * (base + per_peer * num_other_peers) @@ -113,13 +114,19 @@ class KND_API sync_session { using ptr = std::shared_ptr; /// Construct sync session + /// @param chain Blockchain reference + /// @param peer Primary peer for header sync + /// @param network Network type (mainnet/testnet) + /// @param config Sync configuration /// @param target_height Override target height (0 = use peer's start_height) + /// @param p2p_node Optional p2p_node for parallel block download (nullptr = sequential) sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, sync_config const& config = {}, - size_t target_height = 0); + size_t target_height = 0, + network::p2p_node* p2p_node = nullptr); /// Run synchronization with peer /// Returns when synced or on error @@ -143,9 +150,13 @@ class KND_API sync_session { ::asio::awaitable sync_headers_batch(); ::asio::awaitable sync_blocks(std::vector const& hashes); + // Background task to persist headers from header_index to database + ::asio::awaitable persist_headers_to_db(size_t start_height, size_t end_height); + blockchain::block_chain& chain_; blockchain::header_organizer organizer_; network::peer_session::ptr peer_; + network::p2p_node* p2p_node_; // Optional: for parallel block download sync_config config_; size_t header_height_{0}; // Current header-sync height (from DB at start) @@ -167,13 +178,15 @@ class KND_API sync_session { /// Create a sync session for a peer /// @param target_height Override target height (0 = use peer's start_height) +/// @param p2p_node Optional p2p_node for parallel block download (nullptr = sequential) [[nodiscard]] KND_API sync_session::ptr make_sync_session( blockchain::block_chain& chain, network::peer_session::ptr peer, domain::config::network network, sync_config const& config = {}, - size_t target_height = 0); + size_t target_height = 0, + network::p2p_node* p2p_node = nullptr); /// Run sync with the best available peer /// Selects peer based on start_height from version message diff --git a/src/node/src/block_download_coordinator.cpp b/src/node/src/block_download_coordinator.cpp new file mode 100644 index 00000000..9881cc03 --- /dev/null +++ b/src/node/src/block_download_coordinator.cpp @@ -0,0 +1,360 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include +#include +#include + +namespace kth::node { + +block_download_coordinator::block_download_coordinator( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config const& config) + : config_(config) + , chain_(chain) + , organizer_(organizer) + , start_height_(start_height) + , target_height_(target_height) + , strand_(::asio::make_strand(executor)) + , next_height_to_assign_(start_height) + , next_height_to_validate_(start_height) + , start_time_(std::chrono::steady_clock::now()) + , validation_queue_(std::make_unique(executor, config.global_window)) +{ + spdlog::debug("[coordinator] Created for blocks {}-{} ({} blocks)", + start_height, target_height, target_height - start_height + 1); +} + +block_download_coordinator::~block_download_coordinator() { + stop(); +} + +// ============================================================================= +// Peer Interface +// ============================================================================= + +::asio::awaitable>> block_download_coordinator::claim_blocks( + peer_ptr const& peer, + size_t max_count) +{ + // Execute on strand to serialize access to shared state + co_return co_await ::asio::co_spawn(strand_, [this, peer, max_count]() -> ::asio::awaitable>> { + if (stopped_ || failed_) { + co_return std::vector>{}; + } + + // Count how many blocks this peer already has in-flight + size_t peer_in_flight = 0; + for (auto const& [height, assignment] : in_flight_) { + if (assignment.peer == peer) { + ++peer_in_flight; + } + } + + // Limit per peer + if (peer_in_flight >= config_.max_blocks_per_peer) { + spdlog::debug("[coordinator] Peer [{}] at limit ({} >= {} max)", + peer->authority(), peer_in_flight, config_.max_blocks_per_peer); + co_return std::vector>{}; + } + + size_t can_claim = std::min(max_count, config_.max_blocks_per_peer - peer_in_flight); + + // Check in-flight limit (don't count pending - those are already downloaded) + size_t total_in_flight = in_flight_.size(); + if (total_in_flight >= config_.global_window) { + spdlog::debug("[coordinator] In-flight window full for peer [{}]: {} >= {} window", + peer->authority(), total_in_flight, config_.global_window); + co_return std::vector>{}; + } + + can_claim = std::min(can_claim, config_.global_window - total_in_flight); + + std::vector> result; + result.reserve(can_claim); + + auto now = std::chrono::steady_clock::now(); + + while (result.size() < can_claim && next_height_to_assign_ <= target_height_) { + uint32_t height = next_height_to_assign_++; + + // Get hash from header organizer + auto hash = get_block_hash(height); + if (hash == null_hash) { + spdlog::warn("[coordinator] No header hash for height {}", height); + set_failed(error::not_found); + break; + } + + // Track assignment + in_flight_[height] = {peer, now}; + result.emplace_back(height, hash); + } + + if (!result.empty()) { + spdlog::debug("[coordinator] Peer [{}] claimed {} blocks ({}-{})", + peer->authority(), result.size(), + result.front().first, result.back().first); + } + + co_return result; + }, ::asio::use_awaitable); +} + +::asio::awaitable block_download_coordinator::block_received( + uint32_t height, + hash_digest const& hash, + block_const_ptr block) +{ + // Execute on strand to serialize access to shared state + co_await ::asio::co_spawn(strand_, [this, height, hash, block = std::move(block)]() -> ::asio::awaitable { + if (stopped_ || failed_) { + co_return; + } + + // Remove from in-flight + auto it = in_flight_.find(height); + if (it != in_flight_.end()) { + in_flight_.erase(it); + } + + // Store in pending buffer + pending_blocks_[height] = std::move(block); + + spdlog::trace("[coordinator] Block {} received, {} pending, next to validate: {}", + height, pending_blocks_.size(), next_height_to_validate_); + + // Try to push ready blocks to validation + flush_pending_to_validation(); + }, ::asio::use_awaitable); +} + +::asio::awaitable block_download_coordinator::peer_disconnected(peer_ptr const& peer) { + // Execute on strand to serialize access to shared state + co_await ::asio::co_spawn(strand_, [this, peer]() -> ::asio::awaitable { + // Find and remove all blocks assigned to this peer + std::vector to_reassign; + for (auto const& [height, assignment] : in_flight_) { + if (assignment.peer == peer) { + to_reassign.push_back(height); + } + } + + for (auto height : to_reassign) { + in_flight_.erase(height); + } + + if (!to_reassign.empty()) { + // Reset assignment pointer to allow these blocks to be reclaimed + // Find the minimum height that was in-flight + uint32_t min_height = *std::min_element(to_reassign.begin(), to_reassign.end()); + if (min_height < next_height_to_assign_) { + next_height_to_assign_ = min_height; + } + + spdlog::info("[coordinator] Peer [{}] disconnected, reassigning {} blocks from height {}", + peer->authority(), to_reassign.size(), min_height); + } + }, ::asio::use_awaitable); +} + +// ============================================================================= +// Validation Pipeline +// ============================================================================= + +::asio::awaitable>> +block_download_coordinator::next_block_to_validate() +{ + if (stopped_ || failed_) { + co_return std::nullopt; + } + + // Try to receive from channel + auto [ec, block_pair] = co_await validation_queue_->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + // Channel closed or error + co_return std::nullopt; + } + + co_return block_pair; +} + +void block_download_coordinator::validation_complete(uint32_t height, code result) { + if (result != error::success) { + spdlog::error("[coordinator] Validation failed at height {}: {}", + height, result.message()); + set_failed(result); + return; + } + + ++blocks_validated_; + + // Check if we're done + if (blocks_validated_.load() >= (target_height_ - start_height_ + 1)) { + spdlog::info("[coordinator] All {} blocks validated", + target_height_ - start_height_ + 1); + validation_queue_->close(); + } +} + +// ============================================================================= +// Status & Control +// ============================================================================= + +void block_download_coordinator::check_timeouts() { + // Post to strand to serialize access + ::asio::post(strand_, [this]() { + if (stopped_ || failed_) { + return; + } + + auto now = std::chrono::steady_clock::now(); + std::vector stalled; + + for (auto const& [height, assignment] : in_flight_) { + auto elapsed = std::chrono::duration_cast( + now - assignment.requested_at); + + if (elapsed > config_.stall_timeout) { + spdlog::warn("[coordinator] Block {} stalled from [{}] ({}s)", + height, assignment.peer->authority(), elapsed.count()); + stalled.push_back(height); + } + } + + // Remove stalled assignments (will be reclaimed) + for (auto height : stalled) { + in_flight_.erase(height); + } + + if (!stalled.empty()) { + // Reset assignment to lowest stalled height + uint32_t min_height = *std::min_element(stalled.begin(), stalled.end()); + if (min_height < next_height_to_assign_) { + next_height_to_assign_ = min_height; + } + spdlog::info("[coordinator] {} stalled blocks reassigned from height {}", + stalled.size(), min_height); + } + }); +} + +bool block_download_coordinator::is_complete() const { + return blocks_validated_.load() >= (target_height_ - start_height_ + 1); +} + +bool block_download_coordinator::has_failed() const { + return failed_.load(); +} + +bool block_download_coordinator::is_stopped() const { + return stopped_.load(); +} + +code block_download_coordinator::failure_reason() const { + return failure_reason_; +} + +void block_download_coordinator::stop() { + if (stopped_.exchange(true)) { + return; // Already stopped + } + + if (validation_queue_) { + validation_queue_->close(); + } +} + +block_download_coordinator::progress block_download_coordinator::get_progress() const { + // This is called from validation pipeline which is on the strand, + // so we can safely read without additional synchronization. + // For extra safety, we use atomics for frequently changing values. + + // Count unique peers with blocks in-flight + boost::unordered_flat_set unique_peers; + for (auto const& [height, assignment] : in_flight_) { + unique_peers.insert(assignment.peer); + } + + return { + .blocks_downloaded = static_cast( + (next_height_to_assign_ - start_height_) - in_flight_.size() + pending_blocks_.size()), + .blocks_validated = blocks_validated_.load(), + .blocks_in_flight = static_cast(in_flight_.size()), + .blocks_pending = static_cast(pending_blocks_.size()), + .active_peers = static_cast(unique_peers.size()), + .start_height = start_height_, + .target_height = target_height_, + .start_time = start_time_ + }; +} + +// ============================================================================= +// Private Helpers +// ============================================================================= + +hash_digest block_download_coordinator::get_block_hash(uint32_t height) const { + // Get hash from header organizer's index + return organizer_.index().get_hash(static_cast(height)); +} + +void block_download_coordinator::flush_pending_to_validation() { + // Push as many consecutive blocks as possible to validation channel + while (!pending_blocks_.empty()) { + auto it = pending_blocks_.find(next_height_to_validate_); + if (it == pending_blocks_.end()) { + // Next block not yet received + break; + } + + // Create the pair to send WITHOUT moving from pending_blocks yet + auto block_pair = std::make_pair(next_height_to_validate_, it->second); + + // Try to send to validation channel + bool sent = validation_queue_->try_send(std::error_code{}, std::move(block_pair)); + + if (!sent) { + // Channel full - block is still safe in pending_blocks, just exit + // Rate-limit this log: only log occasionally to avoid spam + static auto last_log = std::chrono::steady_clock::now(); + auto now = std::chrono::steady_clock::now(); + if (now - last_log > std::chrono::seconds(5)) { + spdlog::warn("[coordinator] Validation channel full at height {} ({} pending)", + next_height_to_validate_, pending_blocks_.size()); + last_log = now; + } + break; + } + + // Success - now remove from pending_blocks + pending_blocks_.erase(it); + ++next_height_to_validate_; + } +} + +void block_download_coordinator::set_failed(code reason) { + if (failed_.exchange(true)) { + return; // Already failed + } + + failure_reason_ = reason; + spdlog::error("[coordinator] Sync failed: {}", reason.message()); + + if (validation_queue_) { + validation_queue_->close(); + } +} + +} // namespace kth::node diff --git a/src/node/src/block_download_coordinator_v2.cpp b/src/node/src/block_download_coordinator_v2.cpp new file mode 100644 index 00000000..14bcca64 --- /dev/null +++ b/src/node/src/block_download_coordinator_v2.cpp @@ -0,0 +1,411 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include + +namespace kth::node { + +block_download_coordinator_v2::block_download_coordinator_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + uint32_t start_height, + uint32_t target_height, + ::asio::any_io_executor executor, + parallel_download_config_v2 const& config) + : config_(config) + , slots_per_round_(config.max_peers * config.slots_multiplier) + , chain_(chain) + , organizer_(organizer) + , start_height_(start_height) + , target_height_(target_height) + , total_chunks_((target_height - start_height + config.chunk_size) / config.chunk_size) + , slots_(slots_per_round_) + , slot_times_(slots_per_round_) + , next_height_to_validate_(start_height) + , start_time_(std::chrono::steady_clock::now()) + , validation_queue_(std::make_unique(executor, 1024)) +{ + // Initialize all slots to FREE + for (size_t i = 0; i < slots_per_round_; ++i) { + slots_[i].store(FREE, std::memory_order_relaxed); + slot_times_[i].store(0, std::memory_order_relaxed); + } + + spdlog::debug("[coordinator_v2] Created for blocks {}-{} ({} blocks, {} chunks, {} slots/round)", + start_height, target_height, target_height - start_height + 1, + total_chunks_, slots_per_round_); +} + +block_download_coordinator_v2::~block_download_coordinator_v2() { + stop(); +} + +// ============================================================================= +// Peer Interface (Lock-Free) +// ============================================================================= + +std::optional block_download_coordinator_v2::claim_chunk() { + if (stopped_.load(std::memory_order_acquire) || failed_.load(std::memory_order_acquire)) { + return std::nullopt; + } + + // Wait if round is being reset + while (resetting_.load(std::memory_order_acquire)) { + std::this_thread::yield(); + } + + uint32_t r = round_.load(std::memory_order_acquire); + + // Search for a FREE slot + for (size_t i = 0; i < slots_per_round_; ++i) { + uint8_t expected = FREE; + if (slots_[i].compare_exchange_strong(expected, IN_PROGRESS, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + // Got slot i + slot_times_[i].store(now_ms(), std::memory_order_release); + + uint32_t chunk_id = r * slots_per_round_ + i; + + // Check if this chunk is beyond our target + auto [block_start, block_end] = chunk_range(chunk_id); + if (block_start > target_height_) { + // No more chunks needed - mark as completed and return nullopt + slots_[i].store(COMPLETED, std::memory_order_release); + return std::nullopt; + } + + spdlog::debug("[coordinator_v2] Claimed chunk {} (slot {}, round {}, blocks {}-{})", + chunk_id, i, r, block_start, block_end); + + return chunk_id; + } + } + + // All slots occupied - try to advance round + // First check if all are COMPLETED + bool all_completed = true; + for (size_t i = 0; i < slots_per_round_; ++i) { + if (slots_[i].load(std::memory_order_acquire) != COMPLETED) { + all_completed = false; + break; + } + } + + if (all_completed) { + try_advance_round(); + // Retry claim after round advance + return claim_chunk(); + } + + // Some slots are IN_PROGRESS - wait for them or timeout will reset them + spdlog::debug("[coordinator_v2] All slots occupied, waiting..."); + return std::nullopt; +} + +std::pair block_download_coordinator_v2::chunk_range(uint32_t chunk_id) const { + uint32_t block_start = start_height_ + chunk_id * config_.chunk_size; + uint32_t block_end = std::min(block_start + static_cast(config_.chunk_size) - 1, target_height_); + return {block_start, block_end}; +} + +hash_digest block_download_coordinator_v2::get_block_hash(uint32_t height) const { + return organizer_.index().get_hash(static_cast(height)); +} + +void block_download_coordinator_v2::chunk_completed(uint32_t chunk_id) { + uint32_t r = chunk_id / slots_per_round_; + size_t slot = chunk_id % slots_per_round_; + + uint32_t current_round = round_.load(std::memory_order_acquire); + if (r != current_round) { + // Old round - ignore + spdlog::debug("[coordinator_v2] Chunk {} completed but from old round {} (current: {})", + chunk_id, r, current_round); + return; + } + + // Mark as completed + slots_[slot].store(COMPLETED, std::memory_order_release); + chunks_completed_.fetch_add(1, std::memory_order_relaxed); + + spdlog::debug("[coordinator_v2] Chunk {} completed (slot {})", chunk_id, slot); + + // Try to advance round if all completed + try_advance_round(); +} + +void block_download_coordinator_v2::chunk_failed(uint32_t chunk_id) { + uint32_t r = chunk_id / slots_per_round_; + size_t slot = chunk_id % slots_per_round_; + + uint32_t current_round = round_.load(std::memory_order_acquire); + if (r != current_round) { + // Old round - ignore + return; + } + + // Reset to FREE so another peer can take it + uint8_t expected = IN_PROGRESS; + if (slots_[slot].compare_exchange_strong(expected, FREE, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + spdlog::info("[coordinator_v2] Chunk {} failed, reset to FREE", chunk_id); + } +} + +// ============================================================================= +// Block Reception & Validation +// ============================================================================= + +void block_download_coordinator_v2::block_received(uint32_t height, block_const_ptr block) { + std::lock_guard lock(validation_mutex_); + + if (stopped_ || failed_) { + return; + } + + // Store in pending buffer + pending_blocks_[height] = std::move(block); + + spdlog::trace("[coordinator_v2] Block {} received, {} pending, next to validate: {}", + height, pending_blocks_.size(), next_height_to_validate_); + + // Try to push ready blocks to validation + flush_pending_to_validation(); +} + +::asio::awaitable>> +block_download_coordinator_v2::next_block_to_validate() +{ + if (stopped_ || failed_) { + co_return std::nullopt; + } + + auto [ec, block_pair] = co_await validation_queue_->async_receive( + ::asio::as_tuple(::asio::use_awaitable)); + + if (ec) { + co_return std::nullopt; + } + + co_return block_pair; +} + +void block_download_coordinator_v2::validation_complete(uint32_t height, code result) { + if (result != error::success) { + spdlog::error("[coordinator_v2] Validation failed at height {}: {}", + height, result.message()); + set_failed(result); + return; + } + + uint32_t validated = blocks_validated_.fetch_add(1, std::memory_order_relaxed) + 1; + + // Check if we're done + if (validated >= (target_height_ - start_height_ + 1)) { + spdlog::info("[coordinator_v2] All {} blocks validated", + target_height_ - start_height_ + 1); + validation_queue_->close(); + } +} + +// ============================================================================= +// Status & Control +// ============================================================================= + +void block_download_coordinator_v2::check_timeouts() { + if (stopped_ || failed_) { + return; + } + + uint64_t now = now_ms(); + uint64_t timeout_ms = std::chrono::duration_cast( + config_.stall_timeout).count(); + + for (size_t i = 0; i < slots_per_round_; ++i) { + if (slots_[i].load(std::memory_order_acquire) == IN_PROGRESS) { + uint64_t assigned_at = slot_times_[i].load(std::memory_order_acquire); + if (assigned_at > 0 && (now - assigned_at) > timeout_ms) { + // Slot stalled - reset to FREE + uint8_t expected = IN_PROGRESS; + if (slots_[i].compare_exchange_strong(expected, FREE, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + uint32_t chunk_id = round_.load(std::memory_order_acquire) * slots_per_round_ + i; + spdlog::warn("[coordinator_v2] Chunk {} (slot {}) timed out, reset to FREE", + chunk_id, i); + } + } + } + } +} + +bool block_download_coordinator_v2::is_complete() const { + auto validated = blocks_validated_.load(std::memory_order_acquire); + auto total = target_height_ - start_height_ + 1; + bool complete = validated >= total; + if (complete) { + spdlog::info("[coordinator_v2] is_complete() = true: validated={}, total={}, start={}, target={}", + validated, total, start_height_, target_height_); + } + return complete; +} + +bool block_download_coordinator_v2::has_failed() const { + return failed_.load(std::memory_order_acquire); +} + +bool block_download_coordinator_v2::is_stopped() const { + return stopped_.load(std::memory_order_acquire); +} + +code block_download_coordinator_v2::failure_reason() const { + return failure_reason_; +} + +void block_download_coordinator_v2::stop() { + if (stopped_.exchange(true, std::memory_order_acq_rel)) { + return; + } + + if (validation_queue_) { + validation_queue_->close(); + } +} + +void block_download_coordinator_v2::peer_started() { + spdlog::info("[coordinator_v2] peer_started() called on coordinator at {}", static_cast(this)); + auto prev = active_peers_.fetch_add(1, std::memory_order_relaxed); + spdlog::info("[coordinator_v2] peer_started() completed, was {}, now {}", prev, prev + 1); +} + +void block_download_coordinator_v2::peer_stopped() { + active_peers_.fetch_sub(1, std::memory_order_relaxed); +} + +block_download_coordinator_v2::progress block_download_coordinator_v2::get_progress() const { + // Count assigned and completed slots in current round + uint32_t in_progress = 0; + uint32_t completed = 0; + for (size_t i = 0; i < slots_per_round_; ++i) { + uint8_t state = slots_[i].load(std::memory_order_acquire); + if (state == IN_PROGRESS) ++in_progress; + else if (state == COMPLETED) ++completed; + } + + // Get pending blocks count + uint32_t pending = 0; + { + std::lock_guard lock(const_cast(validation_mutex_)); + pending = static_cast(pending_blocks_.size()); + } + + return { + .chunks_assigned = in_progress + completed, + .chunks_completed = chunks_completed_.load(std::memory_order_acquire), + .chunks_in_progress = in_progress, + .blocks_validated = blocks_validated_.load(std::memory_order_acquire), + .blocks_pending = pending, + .current_round = round_.load(std::memory_order_acquire), + .start_height = start_height_, + .target_height = target_height_, + .active_peers = active_peers_.load(std::memory_order_acquire), + .start_time = start_time_ + }; +} + +// ============================================================================= +// Private Helpers +// ============================================================================= + +void block_download_coordinator_v2::try_advance_round() { + // Check if all slots are COMPLETED + for (size_t i = 0; i < slots_per_round_; ++i) { + if (slots_[i].load(std::memory_order_acquire) != COMPLETED) { + return; // Not all completed + } + } + + // All completed - try to acquire reset lock + bool expected = false; + if (!resetting_.compare_exchange_strong(expected, true, + std::memory_order_acq_rel, std::memory_order_relaxed)) { + return; // Another thread is resetting + } + + // We have the reset lock + uint32_t old_round = round_.load(std::memory_order_acquire); + uint32_t new_round = old_round + 1; + + // Check if we've processed all chunks + uint32_t chunks_in_new_round = new_round * slots_per_round_; + if (chunks_in_new_round >= total_chunks_) { + // All chunks assigned - no need to advance, sync is almost done + resetting_.store(false, std::memory_order_release); + return; + } + + spdlog::info("[coordinator_v2] Advancing to round {} (chunks {}-{})", + new_round, chunks_in_new_round, chunks_in_new_round + slots_per_round_ - 1); + + // Reset all slots to FREE + for (size_t i = 0; i < slots_per_round_; ++i) { + slots_[i].store(FREE, std::memory_order_relaxed); + slot_times_[i].store(0, std::memory_order_relaxed); + } + + // Advance round counter + round_.store(new_round, std::memory_order_release); + + // Release reset lock + resetting_.store(false, std::memory_order_release); +} + +void block_download_coordinator_v2::flush_pending_to_validation() { + // Must be called with validation_mutex_ held + + while (!pending_blocks_.empty()) { + auto it = pending_blocks_.find(next_height_to_validate_); + if (it == pending_blocks_.end()) { + break; // Next block not yet received + } + + auto block_pair = std::make_pair(next_height_to_validate_, it->second); + + bool sent = validation_queue_->try_send(std::error_code{}, std::move(block_pair)); + if (!sent) { + // Channel full - try again later + break; + } + + pending_blocks_.erase(it); + ++next_height_to_validate_; + } +} + +void block_download_coordinator_v2::set_failed(code reason) { + if (failed_.exchange(true, std::memory_order_acq_rel)) { + return; + } + + failure_reason_ = reason; + spdlog::error("[coordinator_v2] Sync failed: {}", reason.message()); + + if (validation_queue_) { + validation_queue_->close(); + } +} + +uint64_t block_download_coordinator_v2::now_ms() { + return static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch() + ).count() + ); +} + +} // namespace kth::node diff --git a/src/node/src/executor/executor.cpp b/src/node/src/executor/executor.cpp index cc892b42..21817481 100644 --- a/src/node/src/executor/executor.cpp +++ b/src/node/src/executor/executor.cpp @@ -85,16 +85,20 @@ void executor::start_io_thread() { } void executor::stop_io_thread() { + spdlog::debug("[executor] stop_io_thread() - releasing work guard..."); // Release work guard to allow io_context to stop work_guard_.reset(); + spdlog::debug("[executor] stop_io_thread() - stopping io_context..."); // Stop io_context io_context_.stop(); + spdlog::debug("[executor] stop_io_thread() - joining io thread..."); // Wait for thread to finish if (io_thread_.joinable()) { io_thread_.join(); } + spdlog::debug("[executor] stop_io_thread() - done"); } // ============================================================================= @@ -110,6 +114,10 @@ void executor::start_async(start_handler handler) { return; } + // Initialize the run_completed promise/future pair for this run + run_completed_promise_ = std::promise(); + run_completed_future_ = run_completed_promise_.get_future(); + // Initialize output and directory initialize_output("", config_.database.db_mode); @@ -149,6 +157,8 @@ void executor::start_async(start_handler handler) { start_result_ = start_ec; } start_cv_.notify_all(); + // Signal run completed (early exit) so stop() doesn't hang + run_completed_promise_.set_value(); co_return; } @@ -179,7 +189,10 @@ void executor::start_async(start_handler handler) { spdlog::error("[node] Node run ended with error: {}.", run_ec.message()); } - spdlog::debug("[node] Node run() completed."); + spdlog::debug("[node] Node run() completed, signaling run_completed_promise."); + + // Signal that run() has completed - stop() waits for this before destroying the node + run_completed_promise_.set_value(); }, [this, handler](std::exception_ptr ep) { if (ep) { @@ -197,6 +210,9 @@ void executor::start_async(start_handler handler) { start_result_ = error::operation_failed; } start_cv_.notify_all(); + + // Signal run completed (with error) so stop() doesn't hang + run_completed_promise_.set_value(); } }); } @@ -218,24 +234,34 @@ void executor::stop_async(stop_handler handler) { node_->stop(); } - // Spawn cleanup coroutine - ::asio::co_spawn(io_context_, [this, handler]() -> ::asio::awaitable { - // Wait for node to finish + // Cleanup must happen on a separate thread to avoid blocking io_context. + // The cleanup thread waits for run() to complete before calling join(). + std::thread cleanup_thread([this, handler]() { + // CRITICAL: Wait for run() to fully complete before cleanup. + // run() may still be inside chain.organize() when stop() is called. + // We must wait for all coroutines to exit before destroying resources. + spdlog::debug("[executor] Waiting for run() to complete..."); + if (run_completed_future_.valid()) { + run_completed_future_.wait(); + } + spdlog::debug("[executor] run() completed, proceeding with cleanup"); + + // Now it's safe to join (all coroutines have exited) if (node_) { node_->join(); } spdlog::info("[node] Node stopped successfully."); + spdlog::info("[node] Good bye!"); state_ = state::stopped; + // Handler MUST be called LAST - caller may destroy objects after this if (handler) { handler(); } - - spdlog::info("[node] Good bye!"); - co_return; - }, ::asio::detached); + }); + cleanup_thread.detach(); } // ============================================================================= @@ -272,15 +298,30 @@ void executor::stop() { done_promise.set_value(); }); - // Wait for stop to complete + // Wait for stop_async's cleanup coroutine to complete done_future.wait(); + spdlog::debug("[executor] stop() - cleanup coroutine completed, waiting for run() to complete..."); + + // CRITICAL: Wait for run() coroutine to fully complete before destroying the node. + // This ensures all parallel_sync and other coroutines have finished and won't + // access destroyed objects. Without this, we get segfaults on shutdown. + if (run_completed_future_.valid()) { + run_completed_future_.wait(); + } + + spdlog::debug("[executor] stop() - run() completed, destroying node..."); + // Destroy node BEFORE stopping io_context // (node's components use io_context for timer cancellation, etc.) node_.reset(); + spdlog::debug("[executor] stop() - node destroyed, stopping io thread..."); + // Stop IO thread stop_io_thread(); + + spdlog::debug("[executor] stop() - io thread stopped, exiting stop()"); } // Global variable for signal handling (required for std::signal) @@ -291,8 +332,8 @@ namespace { void signal_handler(int signal_number) { // Immediate print to stderr (unbuffered) so user sees it right away // Note: fprintf is async-signal-safe, std::println is not - std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); - std::fflush(stderr); + // std::fprintf(stderr, "\n[node] Signal %d received - initiating shutdown...\n", signal_number); + // std::fflush(stderr); g_signal_received.store(signal_number); } } diff --git a/src/node/src/full_node.cpp b/src/node/src/full_node.cpp index 7460890e..543bd3dd 100644 --- a/src/node/src/full_node.cpp +++ b/src/node/src/full_node.cpp @@ -80,11 +80,14 @@ full_node::full_node(configuration const& configuration) } full_node::~full_node() { + spdlog::debug("[full_node] destructor starting"); // Only stop/join if not already stopped if (!stopped()) { + spdlog::debug("[full_node] destructor - not stopped, calling stop/join"); stop(); join(); } + spdlog::debug("[full_node] destructor - about to destroy members"); } // ============================================================================= @@ -173,19 +176,41 @@ ::asio::awaitable full_node::run_blockchain_subscriber() { } spdlog::debug("[full_node] run_blockchain_subscriber() - channel obtained, entering loop"); - while (blockchain_channel->is_open() && !stopped()) { - auto result = co_await blockchain_channel->async_receive(::asio::as_tuple(::asio::use_awaitable)); - auto& [ec, fork_height, incoming, outgoing] = result; + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); - if (ec) { - break; - } + while (!stopped()) { + // Non-blocking try_receive + size_t fork_height{}; + block_const_ptr_list_const_ptr incoming{}; + block_const_ptr_list_const_ptr outgoing{}; + + bool received = blockchain_channel->try_receive([&](std::error_code ec, size_t fh, auto in, auto out) { + if (!ec) { + fork_height = fh; + incoming = std::move(in); + outgoing = std::move(out); + } + }); - if (!handle_reorganized(error::success, fork_height, incoming, outgoing)) { - unsubscribe_blockchain(blockchain_channel); + if (received) { + if (!handle_reorganized(error::success, fork_height, incoming, outgoing)) { + unsubscribe_blockchain(blockchain_channel); + break; + } + } else if (!blockchain_channel->is_open()) { + // Channel closed break; + } else { + // No data, sleep briefly + timer.expires_after(std::chrono::milliseconds(100)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled + } } } + spdlog::debug("[full_node] run_blockchain_subscriber() exiting"); } #if ! defined(__EMSCRIPTEN__) @@ -194,15 +219,13 @@ ::asio::awaitable full_node::run_sync() { auto executor = co_await ::asio::this_coro::executor; ::asio::steady_timer timer(executor); - constexpr auto retry_delay = std::chrono::seconds(10); - while (!stopped()) { // Wait until we have at least one connected peer - spdlog::debug("[full_node] run_sync() waiting for peers, count={}", network_.connection_count()); while (!stopped() && network_.connection_count() == 0) { - timer.expires_after(std::chrono::milliseconds(500)); + timer.expires_after(std::chrono::milliseconds(100)); auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { + if (ec || stopped()) { + spdlog::debug("[full_node] run_sync() exiting"); co_return; } } @@ -214,34 +237,55 @@ ::asio::awaitable full_node::run_sync() { spdlog::info("[node] Starting initial block sync..."); auto result = co_await sync_from_best_peer(chain_, network_, network_type_); - if (result.error) { - spdlog::warn("[node] Sync failed: {}, retrying in {}s...", - result.error.message(), retry_delay.count()); + if (stopped()) { + co_return; + } - // Wait before retrying - timer.expires_after(retry_delay); + if (result.error) { + spdlog::warn("[node] Sync failed: {} (connected peers: {}), retrying...", + result.error.message(), network_.connection_count()); + // Brief delay to allow maintain_outbound_connections to find new peers + timer.expires_after(std::chrono::milliseconds(500)); auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); - if (ec) { - co_return; // Timer cancelled, node stopping + if (ec || stopped()) { + co_return; } continue; } - spdlog::info("[node] Initial sync complete: {} headers, {} blocks, height {}", - result.headers_received, result.blocks_received, result.final_height); - break; // Sync successful, exit loop + // Check if we actually synced something + if (result.headers_received > 0 || result.blocks_received > 0) { + spdlog::info("[node] Sync progress: {} headers, {} blocks, height {}", + result.headers_received, result.blocks_received, result.final_height); + // Continue syncing - there might be more blocks + if (stopped()) { + co_return; + } + continue; + } + + // No sync happened - no peers ahead of us + // Wait longer before checking again (allows new peers to connect) + spdlog::debug("[node] No peers ahead of us at height {}, waiting for new peers...", + result.final_height); + timer.expires_after(std::chrono::seconds(5)); + auto [ec2] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec2 || stopped()) { + break; // Timer cancelled or stop requested + } } + spdlog::debug("[full_node] run_sync() exiting"); } #endif void full_node::stop() { #if ! defined(__EMSCRIPTEN__) + // IMPORTANT: Only stop the network here, NOT the chain! + // The chain must remain operational until run() completes because + // run_sync() may still be inside chain.organize() when this is called. + // chain_.stop() is called in join() after run() has fully exited. network_.stop(); #endif - - if (!chain_.stop()) { - spdlog::error("[node] Failed to stop blockchain."); - } } void full_node::join() { @@ -249,6 +293,12 @@ void full_node::join() { network_.join(); #endif + // Now that run() has exited (all coroutines done), it's safe to stop the chain. + // This must happen AFTER run() completes to avoid crashes in chain.organize(). + if (!chain_.stop()) { + spdlog::error("[node] Failed to stop blockchain."); + } + if (!chain_.close()) { spdlog::error("[node] Failed to close blockchain."); } diff --git a/src/node/src/parallel_sync.cpp b/src/node/src/parallel_sync.cpp new file mode 100644 index 00000000..bd6b35af --- /dev/null +++ b/src/node/src/parallel_sync.cpp @@ -0,0 +1,376 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace kth::node { + +namespace { + +// ============================================================================= +// Peer Download Loop +// ============================================================================= + +/// Download loop for a single peer +::asio::awaitable peer_download_loop( + block_download_coordinator& coordinator, + network::peer_session::ptr peer, + parallel_download_config const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync] Download loop STARTED for peer [{}]", + peer->authority()); + + // Check initial conditions + spdlog::debug("[parallel_sync] Peer [{}] - checking initial conditions", peer->authority()); + if (coordinator.is_complete()) { + spdlog::debug("[parallel_sync] Peer [{}] - sync already complete, exiting", + peer->authority()); + co_return; + } + if (coordinator.has_failed()) { + spdlog::debug("[parallel_sync] Peer [{}] - sync already failed, exiting", + peer->authority()); + co_return; + } + if (peer->stopped()) { + spdlog::debug("[parallel_sync] Peer [{}] - peer already stopped, exiting", + peer->authority()); + co_return; + } + + spdlog::debug("[parallel_sync] Peer [{}] - entering main loop", peer->authority()); + while (!coordinator.is_complete() && !coordinator.has_failed() && !peer->stopped()) { + // Claim blocks to download + spdlog::debug("[parallel_sync] Peer [{}] - calling claim_blocks", peer->authority()); + auto blocks = co_await coordinator.claim_blocks(peer, config.max_blocks_per_peer); + spdlog::debug("[parallel_sync] Peer [{}] - claim_blocks returned {} blocks", peer->authority(), blocks.size()); + + if (blocks.empty()) { + // No blocks available - wait a bit and retry + spdlog::debug("[parallel_sync] Peer [{}] - claim_blocks returned empty, waiting 100ms...", + peer->authority()); + ::asio::steady_timer timer(executor); + timer.expires_after(std::chrono::milliseconds(100)); + co_await timer.async_wait(::asio::use_awaitable); + continue; + } + + spdlog::info("[parallel_sync] Peer [{}] CLAIMED {} blocks ({}-{}), requesting...", + peer->authority(), blocks.size(), blocks.front().first, blocks.back().first); + + // Request all blocks in ONE getdata message (batch mode) + // This is MUCH faster than requesting one block at a time + auto batch_result = co_await network::request_blocks_batch(*peer, blocks, config.block_timeout); + + if (!batch_result) { + spdlog::warn("[parallel_sync] Failed to get blocks from peer [{}]: {}", + peer->authority(), batch_result.error().message()); + co_await coordinator.peer_disconnected(peer); + // Stop the peer so network can drop it and connect to new peers + peer->stop(batch_result.error()); + co_return; + } + + spdlog::debug("[parallel_sync] Peer [{}] received {} blocks, reporting to coordinator", + peer->authority(), batch_result->size()); + + // Report all received blocks to coordinator + for (auto& block_with_h : *batch_result) { + auto block_ptr = std::make_shared(std::move(block_with_h.block)); + // Get the original hash from the blocks vector + auto it = std::find_if(blocks.begin(), blocks.end(), + [h = block_with_h.height](auto const& p) { return p.first == h; }); + if (it != blocks.end()) { + co_await coordinator.block_received(block_with_h.height, it->second, block_ptr); + } + } + + } + + // Log why we exited + if (coordinator.is_complete()) { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: sync complete", peer->authority()); + } else if (coordinator.has_failed()) { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: sync failed", peer->authority()); + } else if (peer->stopped()) { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: peer stopped", peer->authority()); + } else { + spdlog::debug("[parallel_sync] Peer [{}] - exiting: unknown reason", peer->authority()); + } +} + +// ============================================================================= +// Validation Pipeline +// ============================================================================= + +/// Validation pipeline - validates blocks in order +::asio::awaitable validation_pipeline( + block_download_coordinator& coordinator, + blockchain::block_chain& chain) +{ + spdlog::debug("[parallel_sync] Starting validation pipeline"); + + while (true) { + // Get next block to validate (blocks until available) + auto block_opt = co_await coordinator.next_block_to_validate(); + + if (!block_opt) { + // No more blocks or sync failed + break; + } + + auto const& [height, block] = *block_opt; + + spdlog::trace("[parallel_sync] Validating block at height {}", height); + + // Validate and store block + // Note: organize() validates the block and adds it to the chain. + // headers_pre_validated=true because this is headers-first sync. + auto result = co_await chain.organize(block, /*headers_pre_validated=*/true); + + coordinator.validation_complete(height, result); + + if (result != error::success) { + spdlog::error("[parallel_sync] Block validation failed at height {}: {}", + height, result.message()); + break; + } + + // Log progress periodically + if (height % 1000 == 0) { + auto progress = coordinator.get_progress(); + auto now = std::chrono::steady_clock::now(); + auto elapsed_secs = std::chrono::duration_cast( + now - progress.start_time).count(); + + // Calculate speed and ETA + double blocks_per_sec = elapsed_secs > 0 + ? static_cast(progress.blocks_validated) / static_cast(elapsed_secs) + : 0.0; + + uint32_t total_blocks = progress.target_height - progress.start_height + 1; + uint32_t remaining = total_blocks - progress.blocks_validated; + uint32_t eta_secs = blocks_per_sec > 0 + ? static_cast(static_cast(remaining) / blocks_per_sec) + : 0; + + // Format ETA as HH:MM:SS + uint32_t eta_hours = eta_secs / 3600; + uint32_t eta_mins = (eta_secs % 3600) / 60; + uint32_t eta_s = eta_secs % 60; + + double percent = 100.0 * static_cast(progress.blocks_validated) / + static_cast(total_blocks); + + spdlog::info("[parallel_sync] Height: {} ({:.1f}%) | {:.0f} blk/s | ETA: {:02d}:{:02d}:{:02d} | peers: {} | in-flight: {}", + height, percent, blocks_per_sec, eta_hours, eta_mins, eta_s, + progress.active_peers, progress.blocks_in_flight); + } + } + + spdlog::debug("[parallel_sync] Validation pipeline completed"); +} + +// ============================================================================= +// Timeout Checker +// ============================================================================= + +/// Periodically check for stalled downloads +::asio::awaitable timeout_checker( + block_download_coordinator& coordinator, + parallel_download_config const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + spdlog::debug("[parallel_sync] Starting timeout checker"); + + while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped()) { + timer.expires_after(config.timeout_check_interval); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled + } + + coordinator.check_timeouts(); + } + + spdlog::debug("[parallel_sync] Timeout checker completed"); +} + +} // anonymous namespace + +// ============================================================================= +// Main Parallel Sync Function +// ============================================================================= + +::asio::awaitable parallel_block_sync( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync] Starting parallel block sync from {} to {} ({} blocks)", + start_height, target_height, target_height - start_height + 1); + + // Create coordinator + block_download_coordinator coordinator( + chain, organizer, start_height, target_height, executor, config); + + // Get available peers (async version) + auto peers = co_await network.peers().all(); + if (peers.empty()) { + spdlog::error("[parallel_sync] No peers available for block download"); + co_return parallel_sync_result{ + .error = error::channel_stopped, + .blocks_downloaded = 0, + .blocks_validated = 0, + .final_height = start_height + }; + } + + spdlog::info("[parallel_sync] Using {} peers for parallel download", peers.size()); + + // ========================================================================= + // Structured concurrency with proper shutdown handling: + // - Download loops run in their own group + // - When ALL download loops exit (peers disconnect or sync complete), + // we stop the coordinator to unblock validation/timeout tasks + // ========================================================================= + + kth::task_group all_tasks(executor); + + // Spawn a "download supervisor" that: + // 1. Runs all download loops in a nested task group + // 2. Watches for new peers and adds them dynamically + // 3. When ALL download loops exit, stops the coordinator + all_tasks.spawn([&]() -> ::asio::awaitable { + kth::task_group download_tasks(executor); + + // Track which peers already have download loops (by address string) + boost::unordered_flat_set active_peers; + + // Start initial peers + for (auto const& peer : peers) { + auto addr = peer->authority().to_string(); + active_peers.insert(addr); + spdlog::info("[parallel_sync] Starting download loop for initial peer [{}]", addr); + download_tasks.spawn(peer_download_loop(coordinator, peer, config)); + } + + // Spawn a peer watcher that adds new peers as they connect + download_tasks.spawn([&]() -> ::asio::awaitable { + auto exec = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(exec); + + while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped() && !network.stopped()) { + timer.expires_after(std::chrono::seconds(2)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; // Timer cancelled + } + + // Check if network is stopping + if (network.stopped()) { + spdlog::debug("[parallel_sync] Peer watcher - network stopped, exiting"); + break; + } + + // Check for new peers and clean up dead ones + auto current_peers = co_await network.peers().all(); + + // Build set of currently connected (live) peer addresses + boost::unordered_flat_set live_addrs; + for (auto const& peer : current_peers) { + if (!peer->stopped()) { + live_addrs.insert(peer->authority().to_string()); + } + } + + // Remove dead peers from active_peers so they can reconnect + erase_if(active_peers, [&live_addrs](auto const& addr) { + return !live_addrs.contains(addr); + }); + + // Add new peers + for (auto const& peer : current_peers) { + if (peer->stopped()) { + continue; + } + auto addr = peer->authority().to_string(); + auto [it, inserted] = active_peers.insert(addr); + if (inserted) { + spdlog::debug("[parallel_sync] Spawning download loop for new peer [{}]", addr); + download_tasks.spawn(peer_download_loop(coordinator, peer, config)); + spdlog::info("[parallel_sync] Added new peer [{}] to download pool (total: {})", + addr, active_peers.size()); + } + } + } + spdlog::debug("[parallel_sync] Peer watcher exiting"); + }()); + + // Wait for all download loops to complete + co_await download_tasks.join(); + + // All downloads done - stop coordinator to unblock validation pipeline + spdlog::debug("[parallel_sync] All download loops exited, stopping coordinator"); + coordinator.stop(); + }()); + + // Spawn validation pipeline + all_tasks.spawn(validation_pipeline(coordinator, chain)); + + // Spawn timeout checker + all_tasks.spawn(timeout_checker(coordinator, config)); + + // Wait for all tasks to complete + co_await all_tasks.join(); + + // Build result + auto progress = coordinator.get_progress(); + parallel_sync_result result{ + .error = coordinator.has_failed() ? coordinator.failure_reason() : error::success, + .blocks_downloaded = progress.blocks_downloaded, + .blocks_validated = progress.blocks_validated, + .final_height = start_height + progress.blocks_validated - 1 + }; + + if (coordinator.is_complete()) { + spdlog::info("[parallel_sync] Parallel sync completed: {} blocks validated", + progress.blocks_validated); + } else if (coordinator.has_failed()) { + spdlog::error("[parallel_sync] Parallel sync failed: {}", + coordinator.failure_reason().message()); + } else { + spdlog::warn("[parallel_sync] Parallel sync interrupted: {} blocks validated", + progress.blocks_validated); + } + + co_return result; +} + +} // namespace kth::node diff --git a/src/node/src/parallel_sync_v2.cpp b/src/node/src/parallel_sync_v2.cpp new file mode 100644 index 00000000..cd7e46a7 --- /dev/null +++ b/src/node/src/parallel_sync_v2.cpp @@ -0,0 +1,382 @@ +// Copyright (c) 2016-2025 Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace kth::node { + +namespace { + +// ============================================================================= +// Peer Download Loop (Lock-Free) +// ============================================================================= + +::asio::awaitable peer_download_loop_v2( + block_download_coordinator_v2& coordinator, + network::peer_session::ptr peer, + parallel_download_config_v2 config) // Pass by value to ensure lifetime +{ + spdlog::info("[parallel_sync_v2] Download loop ENTERING for peer [{}], coordinator at {}", + peer->authority(), static_cast(&coordinator)); + + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync_v2] Download loop got executor for peer [{}], coordinator at {}", + peer->authority(), static_cast(&coordinator)); + + coordinator.peer_started(); + spdlog::info("[parallel_sync_v2] Download loop STARTED for peer [{}] (active peers: {})", + peer->authority(), coordinator.get_progress().active_peers); + + // RAII guard to decrement peer count on exit + struct peer_guard { + block_download_coordinator_v2& coord; + std::string addr; + ~peer_guard() { + coord.peer_stopped(); + spdlog::info("[parallel_sync_v2] Download loop ENDED for peer [{}] (active peers: {})", + addr, coord.get_progress().active_peers); + } + } guard{coordinator, peer->authority().to_string()}; + + while (!coordinator.is_complete() && !coordinator.has_failed() && !peer->stopped()) { + // Claim a chunk (lock-free!) + auto chunk_opt = coordinator.claim_chunk(); + + if (!chunk_opt) { + // No chunks available - wait a bit and retry + spdlog::debug("[parallel_sync_v2] Peer [{}] - no chunks available, waiting...", + peer->authority()); + ::asio::steady_timer timer(executor); + timer.expires_after(std::chrono::milliseconds(100)); + co_await timer.async_wait(::asio::use_awaitable); + continue; + } + + uint32_t chunk_id = *chunk_opt; + auto [block_start, block_end] = coordinator.chunk_range(chunk_id); + + spdlog::debug("[parallel_sync_v2] Peer [{}] claimed chunk {} (blocks {}-{})", + peer->authority(), chunk_id, block_start, block_end); + + // Build block request list + std::vector> blocks; + for (uint32_t h = block_start; h <= block_end; ++h) { + auto hash = coordinator.get_block_hash(h); + if (hash == null_hash) { + spdlog::error("[parallel_sync_v2] No hash for height {}", h); + coordinator.chunk_failed(chunk_id); + continue; + } + blocks.emplace_back(h, hash); + } + + if (blocks.empty()) { + coordinator.chunk_completed(chunk_id); + continue; + } + + // Request blocks from peer + auto batch_result = co_await network::request_blocks_batch( + *peer, blocks, config.stall_timeout); + + if (!batch_result) { + spdlog::warn("[parallel_sync_v2] Failed to get blocks from peer [{}]: {}", + peer->authority(), batch_result.error().message()); + coordinator.chunk_failed(chunk_id); + peer->stop(batch_result.error()); + co_return; + } + + spdlog::debug("[parallel_sync_v2] Peer [{}] received {} blocks for chunk {}", + peer->authority(), batch_result->size(), chunk_id); + + // Report received blocks + for (auto& block_with_h : *batch_result) { + auto block_ptr = std::make_shared( + std::move(block_with_h.block)); + coordinator.block_received(block_with_h.height, block_ptr); + } + + // Mark chunk as completed + coordinator.chunk_completed(chunk_id); + } + // peer_guard destructor will log exit and decrement peer count +} + +// ============================================================================= +// Validation Pipeline +// ============================================================================= + +::asio::awaitable validation_pipeline_v2( + block_download_coordinator_v2& coordinator, + blockchain::block_chain& chain) +{ + spdlog::debug("[parallel_sync_v2] Starting validation pipeline"); + + while (true) { + auto block_opt = co_await coordinator.next_block_to_validate(); + + if (!block_opt) { + break; + } + + auto const& [height, block] = *block_opt; + + spdlog::trace("[parallel_sync_v2] Validating block at height {}", height); + + auto result = co_await chain.organize(block, /*headers_pre_validated=*/true); + + coordinator.validation_complete(height, result); + + if (result != error::success) { + spdlog::error("[parallel_sync_v2] Block validation failed at height {}: {}", + height, result.message()); + break; + } + + // Log progress periodically + if (height % 1000 == 0) { + auto progress = coordinator.get_progress(); + auto now = std::chrono::steady_clock::now(); + auto elapsed_secs = std::chrono::duration_cast( + now - progress.start_time).count(); + + double blocks_per_sec = elapsed_secs > 0 + ? static_cast(progress.blocks_validated) / static_cast(elapsed_secs) + : 0.0; + + uint32_t total_blocks = progress.target_height - progress.start_height + 1; + uint32_t remaining = total_blocks - progress.blocks_validated; + uint32_t eta_secs = blocks_per_sec > 0 + ? static_cast(static_cast(remaining) / blocks_per_sec) + : 0; + + uint32_t eta_hours = eta_secs / 3600; + uint32_t eta_mins = (eta_secs % 3600) / 60; + uint32_t eta_s = eta_secs % 60; + + double percent = 100.0 * static_cast(progress.blocks_validated) / + static_cast(total_blocks); + + spdlog::info("[parallel_sync_v2] Height: {} ({:.1f}%) | {:.0f} blk/s | ETA: {:02d}:{:02d}:{:02d} | peers: {} | in-flight: {} | pending: {}", + height, percent, blocks_per_sec, eta_hours, eta_mins, eta_s, + progress.active_peers, progress.chunks_in_progress, progress.blocks_pending); + } + } + + spdlog::debug("[parallel_sync_v2] Validation pipeline completed"); +} + +// ============================================================================= +// Timeout Checker +// ============================================================================= + +::asio::awaitable timeout_checker_v2( + block_download_coordinator_v2& coordinator, + parallel_download_config_v2 const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(executor); + + spdlog::debug("[parallel_sync_v2] Starting timeout checker"); + + while (!coordinator.is_complete() && !coordinator.has_failed() && !coordinator.is_stopped()) { + timer.expires_after(config.timeout_check_interval); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + break; + } + + coordinator.check_timeouts(); + } + + spdlog::debug("[parallel_sync_v2] Timeout checker completed"); +} + +} // anonymous namespace + +// ============================================================================= +// Main Parallel Sync V2 Function +// ============================================================================= + +::asio::awaitable parallel_block_sync_v2( + blockchain::block_chain& chain, + blockchain::header_organizer& organizer, + network::p2p_node& network, + uint32_t start_height, + uint32_t target_height, + parallel_download_config_v2 const& config) +{ + auto executor = co_await ::asio::this_coro::executor; + + spdlog::info("[parallel_sync_v2] Starting parallel block sync from {} to {} ({} blocks)", + start_height, target_height, target_height - start_height + 1); + + // Create coordinator + block_download_coordinator_v2 coordinator( + chain, organizer, start_height, target_height, executor, config); + + spdlog::info("[parallel_sync_v2] Coordinator created at address {}", static_cast(&coordinator)); + + // Get available peers + auto peers = co_await network.peers().all(); + if (peers.empty()) { + spdlog::error("[parallel_sync_v2] No peers available for block download"); + co_return parallel_sync_result_v2{ + .error = error::channel_stopped, + .blocks_downloaded = 0, + .blocks_validated = 0, + .final_height = start_height + }; + } + + spdlog::info("[parallel_sync_v2] Using {} peers for parallel download", peers.size()); + + kth::task_group all_tasks(executor); + + // Spawn download supervisor + all_tasks.spawn([&]() -> ::asio::awaitable { + kth::task_group download_tasks(executor); + + boost::unordered_flat_set active_peers; + + // Start initial peers + for (auto const& peer : peers) { + auto addr = peer->authority().to_string(); + active_peers.insert(addr); + spdlog::info("[parallel_sync_v2] Starting download loop for initial peer [{}]", addr); + download_tasks.spawn(peer_download_loop_v2(coordinator, peer, config)); + } + + // Peer watcher - monitors for new peer connections and adds them to download pool + download_tasks.spawn([&]() -> ::asio::awaitable { + auto exec = co_await ::asio::this_coro::executor; + ::asio::steady_timer timer(exec); + + spdlog::info("[parallel_sync_v2] Peer watcher STARTED"); + + while (true) { + // Check exit conditions with logging + if (coordinator.is_complete()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator complete"); + break; + } + if (coordinator.has_failed()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator failed"); + break; + } + if (coordinator.is_stopped()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: coordinator stopped"); + break; + } + if (network.stopped()) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: network stopped"); + break; + } + + timer.expires_after(std::chrono::seconds(2)); + auto [ec] = co_await timer.async_wait(::asio::as_tuple(::asio::use_awaitable)); + if (ec) { + spdlog::info("[parallel_sync_v2] Peer watcher exiting: timer cancelled (ec={})", ec.message()); + break; + } + + auto current_peers = co_await network.peers().all(); + + boost::unordered_flat_set live_addrs; + size_t stopped_count = 0; + for (auto const& peer : current_peers) { + if (!peer->stopped()) { + live_addrs.insert(peer->authority().to_string()); + } else { + ++stopped_count; + } + } + + spdlog::info("[parallel_sync_v2] Peer watcher check: {} total, {} live, {} stopped, {} tracked", + current_peers.size(), live_addrs.size(), stopped_count, active_peers.size()); + + // Remove disconnected peers from tracking + auto removed = erase_if(active_peers, [&live_addrs](auto const& addr) { + return !live_addrs.contains(addr); + }); + if (removed > 0) { + spdlog::info("[parallel_sync_v2] Removed {} disconnected peers from tracking", removed); + } + + // Add new peers + for (auto const& peer : current_peers) { + if (peer->stopped()) continue; + auto addr = peer->authority().to_string(); + auto [it, inserted] = active_peers.insert(addr); + if (inserted) { + spdlog::info("[parallel_sync_v2] Adding new peer [{}] to download pool (tracked: {})", + addr, active_peers.size()); + try { + download_tasks.spawn(peer_download_loop_v2(coordinator, peer, config)); + spdlog::info("[parallel_sync_v2] Spawn completed for peer [{}]", addr); + } catch (std::exception const& e) { + spdlog::error("[parallel_sync_v2] Exception spawning peer [{}]: {}", addr, e.what()); + } + } + } + } + }()); + + co_await download_tasks.join(); + + spdlog::debug("[parallel_sync_v2] All download loops exited, stopping coordinator"); + coordinator.stop(); + }()); + + // Spawn validation pipeline + all_tasks.spawn(validation_pipeline_v2(coordinator, chain)); + + // Spawn timeout checker + all_tasks.spawn(timeout_checker_v2(coordinator, config)); + + // Wait for all tasks + co_await all_tasks.join(); + + // Build result + auto progress = coordinator.get_progress(); + parallel_sync_result_v2 result{ + .error = coordinator.has_failed() ? coordinator.failure_reason() : error::success, + .blocks_downloaded = progress.chunks_completed * static_cast(config.chunk_size), + .blocks_validated = progress.blocks_validated, + .final_height = start_height + progress.blocks_validated - 1 + }; + + if (coordinator.is_complete()) { + spdlog::info("[parallel_sync_v2] Parallel sync completed: {} blocks validated", + progress.blocks_validated); + } else if (coordinator.has_failed()) { + spdlog::error("[parallel_sync_v2] Parallel sync failed: {}", + coordinator.failure_reason().message()); + } else { + spdlog::warn("[parallel_sync_v2] Parallel sync interrupted: {} blocks validated", + progress.blocks_validated); + } + + co_return result; +} + +} // namespace kth::node diff --git a/src/node/src/parser.cpp b/src/node/src/parser.cpp index 70f250f8..f50911f7 100644 --- a/src/node/src/parser.cpp +++ b/src/node/src/parser.cpp @@ -95,8 +95,8 @@ void parser::set_default_configuration() { // Logs will slow things if not rotated. configured.network.rotation_size = 10000000; - // With block-first sync the count should be low until complete. - configured.network.outbound_connections = 2; + // Headers-first sync allows parallel block downloads from multiple peers. + configured.network.outbound_connections = 8; // A node allows 1000 host names by default. configured.network.host_pool_capacity = 1000; diff --git a/src/node/src/sync_session.cpp b/src/node/src/sync_session.cpp index c073af1a..884efb1d 100644 --- a/src/node/src/sync_session.cpp +++ b/src/node/src/sync_session.cpp @@ -9,16 +9,31 @@ #include #include +#include #include +#include #include #include +#include +#include namespace kth::node { using namespace kth::blockchain; using namespace kth::network; +// "Permanent" ban duration - 10 years in seconds +// Using a large but safe value instead of hours::max() to avoid overflow +constexpr auto permanent_ban_duration = std::chrono::seconds(10 * 365 * 24 * 60 * 60); + +// Forward declaration - defined at end of file +static ::asio::awaitable persist_headers_background( + block_chain& chain, + header_index const& index, + size_t start_height, + size_t end_height); + // ============================================================================= // Construction // ============================================================================= @@ -28,10 +43,12 @@ sync_session::sync_session( peer_session::ptr peer, domain::config::network network, sync_config const& config, - size_t target_height) + size_t target_height, + p2p_node* p2p_node) : chain_(chain) , organizer_(chain.headers(), chain.chain_settings(), network) , peer_(std::move(peer)) + , p2p_node_(p2p_node) , config_(config) { // Get current chain heights (header-sync and block-sync) @@ -72,9 +89,10 @@ sync_session::ptr make_sync_session( peer_session::ptr peer, domain::config::network network, sync_config const& config, - size_t target_height) + size_t target_height, + p2p_node* p2p_node) { - return std::make_shared(chain, peer, network, config, target_height); + return std::make_shared(chain, peer, network, config, target_height, p2p_node); } // ============================================================================= @@ -85,7 +103,7 @@ ::asio::awaitable sync_session::run() { sync_result result{}; spdlog::info("[sync] Starting headers-first sync with [{}], header-sync: {}, block-sync: {}", - peer_->authority(), header_height_, block_height_); + peer_->authority_with_agent(), header_height_, block_height_); // Check peer version supports headers-first if (peer_->negotiated_version() < config_.minimum_version) { @@ -112,18 +130,18 @@ ::asio::awaitable sync_session::run() { spdlog::info("[sync] Phase 1: Syncing headers from [{}], target height {}, current {}, need ~{} headers", peer_->authority(), target_height_, current_header_height, headers_to_sync); - // Log memory allocator info - if (kth::is_jemalloc_active()) { - spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); - } else { - spdlog::info("[sync] Memory allocator: system default"); - } + // // Log memory allocator info + // if (kth::is_jemalloc_active()) { + // spdlog::info("[sync] Memory allocator: jemalloc {}", kth::get_jemalloc_version()); + // } else { + // spdlog::info("[sync] Memory allocator: system default"); + // } // Log system memory info - auto const total_mem = kth::get_total_system_memory(); - auto const available_mem = kth::get_available_system_memory(); - spdlog::info("[sync] System memory: total {} MB, available {} MB", - total_mem / (1024 * 1024), available_mem / (1024 * 1024)); + // auto const total_mem = kth::get_total_system_memory(); + // auto const available_mem = kth::get_available_system_memory(); + // spdlog::info("[sync] System memory: total {} MB, available {} MB", + // total_mem / (1024 * 1024), available_mem / (1024 * 1024)); // BCHN-style: Calculate headers sync deadline // Timeout = base + per_header * expected_headers @@ -145,8 +163,8 @@ ::asio::awaitable sync_session::run() { // spdlog::info("[sync] Header cache: optimal size {} headers", optimal_cache); // Measure memory before sync - auto const mem_before = kth::get_resident_memory(); - spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); + // auto const mem_before = kth::get_resident_memory(); + // spdlog::info("[sync] Memory before header sync: {} MB", mem_before / (1024 * 1024)); auto const start_time = std::chrono::steady_clock::now(); int consecutive_timeouts = 0; @@ -227,33 +245,24 @@ ::asio::awaitable sync_session::run() { } // Measure memory after headers received - auto const mem_after_headers = kth::get_resident_memory(); - auto const bytes_per_header = total_headers_ > 0 - ? (mem_after_headers - mem_before) / total_headers_ : 0; - spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", - total_headers_, mem_after_headers / (1024 * 1024), - (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); - - // TODO(fernando): implement DB persistence for headers - // For now headers are kept in memory only (header_index) - // if (organizer_.has_pending()) { - // spdlog::info("[sync] Flushing {} cached headers to database...", - // organizer_.cache_size()); - // auto const db_start = std::chrono::steady_clock::now(); - // - // auto const flush_ec = organizer_.flush(); - // if (flush_ec && flush_ec != error::duplicate_block) { - // spdlog::warn("[sync] Failed to flush headers: {}", flush_ec.message()); - // result.error = flush_ec; - // co_return result; - // } - // - // auto const db_elapsed = std::chrono::steady_clock::now() - db_start; - // auto const db_ms = std::chrono::duration_cast(db_elapsed).count(); - // spdlog::info("[sync] Headers flush completed in {}ms", db_ms); - // } + // auto const mem_after_headers = kth::get_resident_memory(); + // auto const bytes_per_header = total_headers_ > 0 + // ? (mem_after_headers - mem_before) / total_headers_ : 0; + // spdlog::info("[sync] Memory after {} headers: {} MB (delta: {} MB, ~{} bytes/header)", + // total_headers_, mem_after_headers / (1024 * 1024), + // (mem_after_headers - mem_before) / (1024 * 1024), bytes_per_header); + + // NOTE: Header persistence to DB now happens in Phase 2 as a background task + // This allows block sync to proceed immediately while headers are saved auto const final_header_height = organizer_.header_height(); + + // Check why header sync ended + if (!synced_ && peer_->stopped()) { + spdlog::warn("[sync] Header sync peer disconnected at height {} (target was {})", + final_header_height, target_height_); + } + spdlog::info("[sync] Phase 1 complete: synced to height {} ({} new headers) from [{}]", final_header_height, total_headers_, peer_->authority()); @@ -264,32 +273,93 @@ ::asio::awaitable sync_session::run() { } // ========================================================================== - // PHASE 2: Download blocks + // PHASE 2: Download blocks (with parallel header persistence) // ========================================================================== auto const final_header_height = organizer_.header_height(); + + // Spawn background task to persist headers to database + // This runs in parallel with block sync - headers are in memory for block validation + // but also being written to DB so restart won't require re-syncing headers + { + // Get current DB header height to determine what needs persisting + auto const db_heights = chain_.get_last_heights(); + size_t db_header_height = db_heights ? db_heights->first : 0; + + // Only persist if we have new headers beyond what's in DB + if (final_header_height > 0 && size_t(final_header_height) > db_header_height) { + auto executor = co_await ::asio::this_coro::executor; + + // Spawn persist task in background (detached) + // Uses references to chain_ and index which outlive sync_session + ::asio::co_spawn(executor, + persist_headers_background( + chain_, + organizer_.index(), + db_header_height + 1, + static_cast(final_header_height)), + ::asio::detached); + } + } + if (block_height_ < final_header_height) { - // Get block hashes from header_index (not database - headers are in memory) auto const blocks_to_download = final_header_height - block_height_; spdlog::info("[sync] Phase 2: Need to download {} blocks ({} to {})", blocks_to_download, block_height_ + 1, final_header_height); - std::vector block_hashes; - block_hashes.reserve(blocks_to_download); + // Use parallel block sync if p2p_node is available + if (p2p_node_ != nullptr) { + spdlog::info("[sync] Phase 2: Using parallel block download from multiple peers"); + + // Convert sync_config to parallel_download_config_v2 (lock-free coordinator) + parallel_download_config_v2 parallel_config{ + .chunk_size = 16, // Blocks per chunk (Bitcoin protocol limit) + .slots_multiplier = 100, // slots_per_round = max_peers * 100 + .max_peers = 8, + .stall_timeout = std::chrono::seconds(config_.block_stalling_timeout), + .timeout_check_interval = std::chrono::seconds(5) + }; + + auto parallel_result = co_await parallel_block_sync_v2( + chain_, + organizer_, + *p2p_node_, + static_cast(block_height_ + 1), + static_cast(final_header_height), + parallel_config); + + if (parallel_result.error) { + spdlog::error("[sync] Parallel block sync failed: {}", + parallel_result.error.message()); + result.error = parallel_result.error; + co_return result; + } - // During IBD, headers are added in order, so index == height for main chain - auto& idx = organizer_.index(); - for (size_t h = block_height_ + 1; h <= size_t(final_header_height); ++h) { - block_hashes.push_back(idx.get_hash(h)); - } + total_blocks_ = parallel_result.blocks_validated; + block_height_ = parallel_result.final_height; - spdlog::info("[sync] Phase 2: Downloading {} blocks from [{}]", - block_hashes.size(), peer_->authority()); + spdlog::info("[sync] Phase 2 complete: {} blocks validated via parallel sync", + parallel_result.blocks_validated); - auto ec = co_await sync_blocks(block_hashes); - if (ec) { - result.error = ec; - co_return result; + } else { + // Fallback to sequential download from single peer + spdlog::info("[sync] Phase 2: Using sequential block download from [{}]", + peer_->authority()); + + std::vector block_hashes; + block_hashes.reserve(blocks_to_download); + + // During IBD, headers are added in order, so index == height for main chain + auto& idx = organizer_.index(); + for (size_t h = block_height_ + 1; h <= size_t(final_header_height); ++h) { + block_hashes.push_back(idx.get_hash(h)); + } + + auto ec = co_await sync_blocks(block_hashes); + if (ec) { + result.error = ec; + co_return result; + } } } @@ -599,12 +669,28 @@ ::asio::awaitable sync_from_best_peer( { sync_result result{}; - // Get current chain heights + // Get current chain heights - use header index for sync selection + // During headers-first sync, header index > persisted headers > blocks size_t our_block_height = 0; + size_t our_db_header_height = 0; auto const heights = chain.get_last_heights(); if (heights) { + our_db_header_height = heights->first; our_block_height = heights->second; } + // Header index may have more headers than persisted to DB + size_t our_header_height = chain.headers().size(); + if (our_header_height > 0) { + --our_header_height; // size() is count, height is count-1 + } + + // For peer selection: + // - If we need blocks (block_height < header_height), use block_height + // so we select peers that can give us blocks + // - If headers and blocks are synced, use header_height for new blocks + size_t our_sync_height = (our_block_height < our_header_height) + ? our_block_height // Need blocks - select peers ahead of our block height + : std::max({our_header_height, our_db_header_height, our_block_height}); // BCHN-style: don't wait for minimum peers, start sync immediately // when any suitable peer is available @@ -618,6 +704,31 @@ ::asio::awaitable sync_from_best_peer( co_return result; } + // Peers below max checkpoint are useless for sync + auto const max_checkpoint_height = chain.chain_settings().max_checkpoint_height; + + // Filter out peers below max checkpoint + auto const initial_peer_count = peers.size(); + peers.erase( + std::remove_if(peers.begin(), peers.end(), + [max_checkpoint_height](auto const& peer) { + auto version = peer->peer_version(); + return !version || size_t(version->start_height()) < max_checkpoint_height; + }), + peers.end()); + + if (peers.empty()) { + spdlog::warn("[sync] No peers at or above checkpoint height {} (filtered {} peers)", + max_checkpoint_height, initial_peer_count); + result.error = error::channel_stopped; + co_return result; + } + + if (peers.size() < initial_peer_count) { + spdlog::debug("[sync] Filtered {} peers below checkpoint height {}", + initial_peer_count - peers.size(), max_checkpoint_height); + } + // Count peers by type for logging size_t preferred_count = 0; size_t full_node_count = 0; @@ -640,16 +751,28 @@ ::asio::awaitable sync_from_best_peer( } } - spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), our height: {}, max peer height: {}", - peers.size(), preferred_count, full_node_count, our_block_height, max_peer_height); + spdlog::info("[sync] Selecting sync peer from {} peers ({} preferred, {} full nodes), " + "our height: {} (headers: {}, blocks: {}), checkpoint: {}, max peer: {}", + peers.size(), preferred_count, full_node_count, + our_sync_height, our_header_height, our_block_height, max_checkpoint_height, max_peer_height); // Select best peer using BCHN logic - auto best_peer = select_sync_peer(peers, our_block_height); + auto best_peer = select_sync_peer(peers, our_sync_height); if (!best_peer) { - spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_block_height); + // Check if there are peers with higher height that we couldn't sync from + // (e.g., all were banned or filtered out) + if (max_peer_height > our_sync_height) { + spdlog::info("[sync] No suitable peers found among {} remaining (none ahead of height {})", + peers.size(), our_sync_height); + result.error = error::operation_failed; + result.final_height = our_sync_height; + co_return result; + } + // Truly synced - no peers have higher height + spdlog::info("[sync] No peers ahead of us (height {}), already synced?", our_sync_height); result.error = error::success; - result.final_height = our_block_height; + result.final_height = our_sync_height; co_return result; } @@ -658,10 +781,11 @@ ::asio::awaitable sync_from_best_peer( spdlog::info("[sync] Selected {} peer [{}] with height {} for sync (target: {})", best_peer->is_preferred_download() ? "preferred" : "fallback", - best_peer->authority(), best_height, max_peer_height); + best_peer->authority_with_agent(), best_height, max_peer_height); // Run sync with selected peer, using max_peer_height as target - auto session = make_sync_session(chain, best_peer, network, config, max_peer_height); + // Pass p2p_node to enable parallel block download + auto session = make_sync_session(chain, best_peer, network, config, max_peer_height, &p2p); result = co_await session->run(); // BCHN-style: If sync failed (including timeout), try another peer @@ -669,18 +793,23 @@ ::asio::awaitable sync_from_best_peer( if (result.error) { if (result.timed_out) { spdlog::warn("[sync] Peer [{}] timed out (too slow), disconnecting and trying another...", - best_peer->authority()); + best_peer->authority_with_agent()); // BCHN disconnects slow peers best_peer->stop(error::channel_timeout); } else if (result.error == error::checkpoints_failed) { // BCHN bans peers that send headers failing checkpoint validation // This typically indicates a peer on a different chain (BSV, etc.) - spdlog::warn("[sync] Peer [{}] sent headers failing checkpoint (wrong chain?), banning...", - best_peer->authority()); - p2p.ban_peer(best_peer, std::chrono::hours{24}, network::ban_reason::checkpoint_failed); + spdlog::warn("[sync] Peer [{}] sent headers failing checkpoint (wrong chain?), banning permanently...", + best_peer->authority_with_agent()); + p2p.ban_peer(best_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + } else if (result.error == error::store_block_missing_parent) { + // Headers don't connect to our chain - peer is likely on a different chain + spdlog::warn("[sync] Peer [{}] sent headers that don't connect (wrong chain?), banning permanently...", + best_peer->authority_with_agent()); + p2p.ban_peer(best_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); } else { spdlog::warn("[sync] Sync with [{}] failed: {}, trying another peer...", - best_peer->authority(), result.error.message()); + best_peer->authority_with_agent(), result.error.message()); } // Remove failed peer from consideration and try again @@ -688,11 +817,15 @@ ::asio::awaitable sync_from_best_peer( std::remove(peers.begin(), peers.end(), best_peer), peers.end()); + spdlog::debug("[sync] {} peers remaining after removing failed peer", peers.size()); + // Retry with remaining peers until we succeed or run out of peers int retry = 0; while (!peers.empty()) { - auto retry_peer = select_sync_peer(peers, our_block_height); + auto retry_peer = select_sync_peer(peers, our_sync_height); if (!retry_peer) { + spdlog::info("[sync] No suitable peers found among {} remaining (none ahead of height {})", + peers.size(), our_sync_height); break; } @@ -702,9 +835,9 @@ ::asio::awaitable sync_from_best_peer( spdlog::info("[sync] Retry {}: {} peer [{}] height {} (target: {})", retry, retry_peer->is_preferred_download() ? "preferred" : "fallback", - retry_peer->authority(), retry_height, max_peer_height); + retry_peer->authority_with_agent(), retry_height, max_peer_height); - auto retry_session = make_sync_session(chain, retry_peer, network, config, max_peer_height); + auto retry_session = make_sync_session(chain, retry_peer, network, config, max_peer_height, &p2p); result = co_await retry_session->run(); if (!result.error) { @@ -713,13 +846,18 @@ ::asio::awaitable sync_from_best_peer( if (result.timed_out) { spdlog::warn("[sync] Retry peer [{}] timed out, disconnecting...", - retry_peer->authority()); + retry_peer->authority_with_agent()); retry_peer->stop(error::channel_timeout); } else if (result.error == error::checkpoints_failed) { // Ban peers that fail checkpoint (wrong chain) - spdlog::warn("[sync] Retry peer [{}] sent headers failing checkpoint (wrong chain?), banning...", - retry_peer->authority()); - p2p.ban_peer(retry_peer, std::chrono::hours{24}, network::ban_reason::checkpoint_failed); + spdlog::warn("[sync] Retry peer [{}] sent headers failing checkpoint (wrong chain?), banning permanently...", + retry_peer->authority_with_agent()); + p2p.ban_peer(retry_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); + } else if (result.error == error::store_block_missing_parent) { + // Headers don't connect - wrong chain + spdlog::warn("[sync] Retry peer [{}] sent headers that don't connect (wrong chain?), banning permanently...", + retry_peer->authority_with_agent()); + p2p.ban_peer(retry_peer, permanent_ban_duration, network::ban_reason::checkpoint_failed); } // Remove this peer and try next @@ -732,4 +870,80 @@ ::asio::awaitable sync_from_best_peer( co_return result; } +// ============================================================================= +// Header Persistence (Background Task) +// ============================================================================= + +// Free function for header persistence - captures only what it needs +// so it can safely run after sync_session is destroyed +static ::asio::awaitable persist_headers_background( + block_chain& chain, + header_index const& index, + size_t start_height, + size_t end_height) +{ + if (start_height > end_height) { + spdlog::debug("[sync] No headers to persist (start {} > end {})", start_height, end_height); + co_return; + } + + auto const total_to_persist = end_height - start_height + 1; + spdlog::info("[sync] Starting background header persistence: {} headers ({} to {})", + total_to_persist, start_height, end_height); + + auto const persist_start = std::chrono::steady_clock::now(); + + // Persist in batches to avoid holding large vectors in memory + constexpr size_t batch_size = 1000; + + size_t persisted = 0; + size_t height = start_height; + + while (height <= end_height) { + // Build batch of headers + domain::chain::header::list batch; + auto const batch_end = std::min(height + batch_size - 1, end_height); + batch.reserve(batch_end - height + 1); + + for (size_t h = height; h <= batch_end; ++h) { + // During IBD, index == height (headers added in order) + batch.push_back(index.get_header(static_cast(h))); + } + + // Persist batch to database + auto const ec = chain.organize_headers_batch(batch, height); + if (ec) { + spdlog::warn("[sync] Header persistence failed at height {}: {}", + height, ec.message()); + // Don't abort - headers are still in memory for block sync + co_return; + } + + persisted += batch.size(); + height = batch_end + 1; + + // Log progress every 50000 headers + if (persisted % 50000 < batch_size) { + auto const elapsed = std::chrono::steady_clock::now() - persist_start; + auto const elapsed_secs = std::chrono::duration_cast(elapsed).count(); + auto const rate = elapsed_secs > 0 ? persisted / elapsed_secs : persisted; + spdlog::info("[sync] Header persistence progress: {}/{} ({}/s)", + persisted, total_to_persist, rate); + } + + // Yield to allow other coroutines to run + co_await ::asio::post(co_await ::asio::this_coro::executor, ::asio::use_awaitable); + } + + auto const elapsed = std::chrono::steady_clock::now() - persist_start; + auto const elapsed_ms = std::chrono::duration_cast(elapsed).count(); + spdlog::info("[sync] Header persistence complete: {} headers in {}ms", + persisted, elapsed_ms); +} + +// Member function wrapper (for declaration compatibility) +::asio::awaitable sync_session::persist_headers_to_db(size_t start_height, size_t end_height) { + co_await persist_headers_background(chain_, organizer_.index(), start_height, end_height); +} + } // namespace kth::node diff --git a/tui_screenshot.png b/tui_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..cdefa169ed42cc29283e5062aa5ef616bb41fcd5 GIT binary patch literal 1232582 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%0A)MV@E7;M-<5kHP<)ZqGUn7s`AAag9n{bmg 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

23+R!HZAc6UrgF@%%FskNR@qO<=kF{DOpnO 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

ff zqWxx9*{?x?i}aVY3Nrm3zRj84&G^m2HnL#M1_{@@H0Rld4~;UPm*i&jySV!eDKHR#Ddbh-dzGSg9yY-}o!Z%)ME zRB1os(*Db6=}Nf}lwPpqI5!l#w#f_VD*Hj4&v)i+`T;uCnvk{h%OA()m3@#C*`U|wjbl;~JiW+0koo!WlqfyciJ|gk zXo0GE*NjcaAT2~YUSoCmc`x-mG%=o``8`y|GoNz9QGYR~)fGtxpkb=q=+jm@O|!@S zf)=ZAufh2rpHDd1w?vAF2QEZtk7_YG$f@_!9ZmG)wg&8C$B=0-*WCutoK5?Ou5R}C zvCTS5JF5Y7&?g}X0!-$!hc+_NQ4I%V!FxP`CvdHce zo*iV7c_WbIErJ<3u#L6oGFnJB&O~$1GEHHeMp&O4d1!@cLgMQ4*62MLWKOQ#S~aiN z&n$l<#9TbHbXEzxDc&2S#MSL}-=Yvmt6%+=hE%xOu#M^2s545u2)AVBkzP1@`7VQe zGk}-2idx&4=9a>^)3dX%JDa&UTzWIcEZ={cX#zAfiJQnpk(vtbDDvy-Qf?J*NqTc^ z_3^!Echqh5f+`@!;>#9LHgTlf@BPsG@F|!eA-sp>#Fg=HJUj0*uT@oKqp8)cHo&T( z6B1EtBog7#*kvN@3ocyA4b^;x=7);|{+4EZ&dL*)-}G9$a}#G9THmx;dy$kjzY=t-x58oOF$(Cc*}s|sHZNqD&|%!{ zwo3mV#9Hz*?b>)r&_ViUSCMQ2&@(>0urF21=w&`j>f*JBlK&Qn%mA?hn2hEz8^o@O z=uKE5pKZ^R1nz2kZNq&|{r6CbnU?vX|JX(UkMgVC%+?Iq*;d!o14JsVIjqKR0bcPX zV0%HgXLVc-PDq2R1qHc#bF{y_%rgxuRZj;GiMnbO4Jp}40}=71V&NheQF9LRB7sH- z8ykewm5AH0Ue(>zKFe}Ab%~C8z`t~*i6C)U?PoTy0ro4<30VVonR!)v^Dd`k4JQ6e z8R~_L!cpQ-#p!1R!t#G*0k|CcQ`PaK2PA)b^;An_O2z>aLd-1_R#C z=9xg)c+lDshFx3qH9cV25Ly-VEllgYA8E=k8k!H%E=X66H<8b&E?@>&NYy)m?Z@JM zUD{(D!6e{p#@>DH5UNWC)UcF;GF+iz*WwNGRp?Xxck%sV7P8eqK-rZ1)q(m}&`fa}_ucwbT>m*ffXdPlau;DOYi*XB z+znVl&HNEds&#I0Kf85#_dD~!`Snl_;4Mhvac3Jf-8dDk@$Oxy<^T^1pt2%uL1&p= z8x=^0Y_wvHS^S_L^-q(3xGY{koQ{d%Jj}5O~1V)m2N{=PH8t zy_(biE~RYMcGkRpyfW3xXLy_BU$4&KIpzZ9{m;9k_F|`UZ7pxY-^X@ND2s&PWt|Fu z@hJqwVLNu^MI8S-%kMzf++YOUTy;{*>-tTQ5tT&__jrukFXOo7tW%efsvXb=n2U9$ zVE92};Rc=d6~k_A`S^gs6AeF9YAn3v2afZ0+Q89TLbrmceS zWNz0m2ML~gBi>VEk;`%JIl}OARymB^IazSCLCXHpGC8ehS0z^brRSpu8ZP4)C6#Yb z=z;W$3P2pDoHDojO;nG>2d&8w%}@)RDCqf3Bj92RXB6{#Z)A%IVeFZI>aaKTP zyk$_e-B;|AltnBM$~=Oz{Uldr7L-aR~c_cSj{H*4!o-=N`1FHPw;(M!C7sDcw+Rtp0JY$ zE6--Twm4l~tCxFLYpC8tcJuTjlINN?DW5ZUzs8Y@{J6R_e4e&R+?*E^=zkrLY;HSC zJGxn&vu?>SOVLqB_QTM1bSid%nG=&@xbo1+Hh|OvgHY$!lLN<44jUD@gT1j}RiugM z(1H*7E6;Trxju^v?_i}SmZhfATL$t+Cig1%-CHkRZ-|1!=zk&()|5X+p}J_)1#Jd% zlGwau)7SOW+Z5>79s%Bnx|(n6dH25+vzlg9dF)-w&n9OT?=tHt=FUlgMj0 zL}xK4mCD;B1vxzKRFx;XZyEu{y?wy1`Fs)^u}vf-Hy;tQ1Iyx?)da%XV%+`d~G?)WAch@VSA=E z62THc9<#V;hS&E@iBOO~ zYoDdg#_e#gNke3#`bM1j`i(~*<>kw2;)-%7^`_-PI-Xft!BHx#mJEr38T^xdv5Qw% zj80poWJArh6u)cJaMX?w ze=>2_%-pEnw8hfBCT@Vku9)RAH~ez($wBJ{YEIOYAC{_)8I9r{Aj4U4-rBtP#0*5k z&*i}pPtt+WQp)qq^%3Wl#-mYYHBI!Wq4y}@+rfIHh%_Q?;Vn^kw6RvmIiL8h^((Q+ zeQwY_`%i$6q-^Tcvk7Vn)^`Y1Dec>*(ww;#hH=?@bI?Z>McRiN zbmrmJ$rBO&ZsMgYqZ%&<4U_%r2p8O+>1I;b@9C8_Qrq1>g*@`6Os$L;bqxT=_O49l17izO10zW>*!;aDPxA2R>KehbJPx+67wtQg(#}rYM zAX007@ny147*A<BFK5kB|J#yY<4of}*18RauR%F!&vZ|DFmd}w)dyHlhMmI~ z5qv-6303wF{3l-YzRkMbyVhkEGf3-Go2?V*J)2+k;93g5%J!a12;nL4&oQ_wwJ78* zhxjmWvWbK7?>RP%cMm?+{hxLk@ZV($P>t%^ueeG64nFPFt6US>w zS{${%h2m>FXq&F;c1O02{U`66i=jhOc`&~GQNLrd*D(v4B~M03LAO!rgGx16&eT@B zSZsUK-2sP81DExzb>vk2i0>64GzYyup}*1BJDV1z)Mc@`R2uXkC|7+oyrmyq0oGq0 zuU|_}-(=5!5*mPM`b3HuIE9tZrv@P$+V%L}9rjn0S|%s1%=(Nm9Dewrm&x~9Tp|dL z--fgvk*mGuoE<+p#IogX7Qf7m#soydpbBkKmm&rM17P?a_p+xcZXJq z3)pZ+8w;R#&9ed|{o{+vi%zzC$v2yQfd`|#GV1$+)Pf$v={D8(tc;dp)>AEyXmWJE z(YnW(GjeD1!^7pvxT8+C_$f>}0%gNPriV;R!C>;%-V+h@=_B`?PFg6`dtZBVNba0<(3eZDM`sr-Bt^j&Q!U*NZ?7 z(V`ZyafPej&wjefyxvj~DzfR!rb2jeMi|M|qZaR31Zkn!Nn=H`aG9+r@72iWOfGY* z@>o-QqI;$cAg;)!a;~UyIYr}ZlyDNyO_BQXwyAM_r%vYEAF)ECpr=wM2ze2G{S;41 zvZwj|N7LSuE6o)C<4Ga@yt|*4SCKrfNSgD^7w@KmVqnA7Jn&g*`1fuBw#oZ4YhKL; z?vsip=3LxVAlJ6I@1)S<|KpqOf8B3)`B!TeE#i>3t}!$C-xYagzbI4r0~p9V5YHt8 z)0`h5JM21471?~{L#>SubQTuKnK${QJclGKJ3rN%1=uHXk6>)HB|gb(mPahi)c%Gp z{AzIz-fg9>I+?H6Uf2D={~Y(QnVa?ZuCR*~+X?v|E4jesS=f#0mj?Np_LmA;^CMoz zG%D>oJ@=q<=j~m;*9)Y)Jh^u*&6dg^aM0G{#F^;Q$)5dYc<+B-d$QV_cfH`VVL(Ce z_&2^=C~uZZT0KaQQdDS^AI``BH7y0td6}91yyE2^%0orWaul(gVqta3n2bVZ0+m`Z6-h3eL> zwF;Za7fcNkq zCe9?C=Rd0#H*(hWihaUyqC*V zqq=eOX63%6+>rgcixWrZ_34=qkx`Ag7)mSx?T6|MGWps$4kl-0m~@ zn?{y77$vpZDk)-yQZx0uueR3r$vB=~Cjk0*tml1y?#Sv-+Ght;?<|ngMERg1!@kXO z4HZZo38*tvGv+WTQfb8R`lXGAP>=rSD)L0Xl2C-+6zT*RHk~+B~wEUSg*X zwQP1l)yyoaq4fxFi%B3i#D%Z6YRuqqt~2WB3%{) zK=+wJr%!cn4UD+qJ@3shW1<#c($6S=ff|_nHZz3nlCKM& zrj!%m*tv)Q87NI>8Gzi!qlD33<3Q$3ntz~#)?R+t^v#ZMALB3hpIf;fiplpn%_(#xHJ2n=S)AOB z75s+NYK*!O%y?!004dnWX*h_9)lT#GZWk?Bt{2e%CaIssc{#ClxIV&0Px+Z4SFKaWUd<3hO;E{@&OUepCEw8s^EP-R=*8l2p<`22lJECAS~d8*hM~d)OxOBt9qC z78xEMc=fnSRKDPVZkgNVFCm{)yi5Ye>o9=0+=k=+c5dU-??1wO>Q=FD!ZOMne|%2- zF&U-w4ux!(c>O^I$(jhCEf)*R@N-yWj(#^2W*f|X<#>hscvZ-v2gsYsXj52ks7Jqe z^PsX7kSFP)a-Z~>KOtl6!NLx&?siYwbKM_7wCeZ)8vbUI_F4*ka?R{6^4`|>2eT=D z#H>8^#F!C@a>EA`c@=YKW>Z(nx|(7hCx~b2rA*7i75> zXdV+tb56Gb)6HG^;-$@PP*;b8dt(wQr{Zv+m3ePxwXk5iD5&j^b1RKX8P)=e$+7zE zLC-%;r^&MI>6lr7fIbEBhduaUS;i6hX``Mx@+EsWL2TR)s8wUq@edydo?uObq@LZ2 zY)XH?0kg*&N`lL#m%nTT9$d<~Px~Yk==v5LWAkKvbl`jb>jO7fKgzm}&i;skQaQA0 zChCFHhdsSOSsI7(=~J2go}HKFbzLyib>=OooOImA4~_nWFe~(*s`H0k3O&?Sc9amu zY%Cu=uuG(vBz{S)gv;I&&$QHw7|thsM_`Z8G?%c{^~u9Po7YmwvaPtu`EM^A z#4qlq9apVMn-d1JiH@nR_x8z?g4d*AX5rHG`Vtc!YWDdX)5yoUB=xnGZ~xk;;E@A; z*(W~!sQoi72g>4q@M{(ZLUVGtjZsC(a6e@zkq5?9$N0- zBdh&9Du0!H7VAByvcobhs15`%@@N6Z(Sut;Q!9KR4OjBZZ%k|be2d{Ugq-NHD*Ubl z8CbQ;8*P}cNgOfIM%+YG9{1djf;%W~uLNu5ZKmvX)X`x`IEG#qh=D;_F1r1%q>zGQBZQ+NEH zKdb1T{u6(@j=c�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%0DdYP@83QqhscHhG-%IW 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 z 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ª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

TfI71 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 F{|jFJ9FPD2 literal 0 HcmV?d00001

@IyzwQ-cSZ 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�b>#m^a&nd^PN*X`zK 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

@IyzwQ-cSZ z&+Wf7UR(#=EoCWn9(>%_%3OXHaSW8||UZFwLTtCOZE6b_( z<-tITP_((vRq60Pmu@kuu&Hn9@FM1qJ0^!~-YNcwEK9L0i?8vp$3I?GMYM^ifs^0SQm-iG)m1wpnel{f-Q6yu6 ze|q!CKzZ%i-klZ}ePTmgVs{xY`ykhD)M#h4k3HaH-e}?xNXBt~f$>Ru^y7#w5{;U<* zCrb7OZs1tn6ZMhtO;7QeSC2F!wV)Mkbca(}ffeNRv~z!$C3dvA_uhdzgwf-{(AE7i z6T%q&T|L9|)#=s6Qkvk$hZ~Gmeg>e*2SaHFultSvVwc#C2bQ=Yof*jI+?LXedg6Uf z>II=m^&JzYcQCs931vwva3SP;?Z{xPnSqogp*gZHg)hF6=~{$;Pq;i@h`vF7qC9t8 zL#v_3z?7&Tk5g2XU;54I?k&=Wq^bf&+lXd(VIOYWl9#jLzau$~oVNKOjq z8j2k6ZaktFR~mAC;wM|u`o*wH&*@vKZ}c0Jcc}cB*}`mv3|5fO6E!f+5iDBlDL$Rc za}v?*=bXj1)-eF~7MN(x_1t<*kEg~`b#LBxMl2k4is=)6vlphVksx_Cr8`kR$7oj+ z->&>!JcarwpS|aDR=#l{RWLR>x4Xx-v+pjExE+>ic}5Cp&bbX_FyUsTgyExXQ=biU z059%hQr?Kww1TX6v)nmxjqYmDb`96JR`gAIJnJgBfYbZq4mX?f*M~o{HU2&z`C4Mv z4~~6^a=2@N!~QlNNGrN6{<~HC8Ln&3GZQ#qfEDUAImtSu$N+j!B_Pm8XB>b&$#+am zubWzM(DcPP*?mcuv~h}7ZVJ3TnkD0nY&t5_Dp2Ps(ydC!%hQQ_n)0^s^@ye6*VmPo z3DHczlxT+Uzr5H~r(?`-p6<58I^br{VCH+btUx_ATRU2iv9OOu*vJ2iS-P(^aaDYS z<6K$zerk^Tj+j=By>+sbZ}$5R=PH4An6(q?vPbI+)XEp__r)G zB`*${+mwk zEcGjO-;fzZtEIj{bBk@ZI<#9wRQ};BNS!GCygC^k?KpZ|)|vNm9VtEucbAU6X#@jv>g09euuUP)q2Ma)9pJ4{xebNw%g&V_#Rb}c3dmJBK;%D(>aY!p}vZRT*wD@ z^?UL*X&y1`pSLM5BSBKiW*#Tu5;-TE6Y;Og>bY4%yuN7EgV8-5I_%0)+JeeJV|mn* zD4eUF{_{od+-QEE%h%1R?DXT^e0=T@UuCX}Wj>wnH$e2$bp+L{Ah*?k!w7*B^ z{Kb;6_q+If^kqxv9l_n$KcH-&ZEGd|D7}4?WCd{9`y_XAtUzvX*UT^fn56z|mASd{ z1n#5P*2heeYm2{1zI=y))_ncWll#YGhr4hHrLMLKP!>HEj9M{L@3tn$1|5}uD2;|v zCnSvcmQP z03e6TT)8BHXF2V$M!fxaamir9SGf|o8mX;1LfCHpBxI#GM*qe3Piu`0_~dR(S{gSw zhdS}KQUubh=(_nN?;8A$&9Hoe=h~;JpZ42xxNv~-!2scz<4(PUKg>oN|asorUz0O)0BP*83KUG4)v#d0`|q;u zxGO-s76bj%PZK>lr+t{V^>z&U$?9=gK>-h%$>9=ECyb1h2v*|N2$C*FH?sjJrA60P zE`Bfl<^B)XyrsKu0RoZ-x+Ago$^bDP>SbCku7SV^2L;k?u2O0RRKKAV&J>E~(g8XW zjzvj0I(b=P*4?_K=@+~<{LmlU`JZXBlVzFh_}7z zXws!Ex)LlVlyR+DJe?&-V<%>s`)u0pU}5z4fxzESMr+NxZ%=)1#!&*o^kz05GY@`iNrL#WsA>;Q?N?Y;cwmC{KZ)D!HYfAQ572679{o!^WzE4IH|!No(-UL$$giPfIf3$0 zN#&8%?!_uLiN!~jafE_Nzt-zc|ikL5@DAze%PcG z8y0e@e(2-TgvLDKzAv;rBKgHOq&gdHg2;{b26=K8=mZO0qs(W^pv?{TjpmazRHo;( zlL}_>FB{1?Z;uiyY+aX?JuoZq*BzSkvy`Mti%_-|hP`fMu=Nn-ku8Puat(gr7r}8o z=k%kN=u%^j(Wh9)tHNXWgjV@P+d+T-cm6r4|LgGuSfTg0f0|E>+!SW{Lh)R51kPGJ ze;;tMV@}?22561%a4fSTHQ)C^YO$Q(*+0Mr38@Ff&EJpCs}{$yEZ`(cozf#7`?y}# zOP!5)04CFC#!UWQ}-I{8;t~vBpvu(2RGC< z%MF1u1n(C)OWdUhEWQ2Kf&JE8O1iIq8Yf@bH z-97Kq9 zlr5`=Rt)$R!EC$jQ-1x)d^!~41r)x*tXCqadUex@A0#&-h?_pn^*j^)egy5_PD#Bc zABJUwAnM?L&uj!;?cz=Pp<9=z)%KhmK6Lkn$A9|(^aO*Nw(N&-R3ZhFzYi`i1X+53 zrQj(cQJ8fDVjwCY`qHv*_vl>wWyFcby@Znjm5U7J9}0 z7B}ZqR`S_etWgARc$&5Bgon=m+aW@WOe6~A{>HC zxQkO^glQnP=lZ;jSJP?IW@?Bn~5cM3^l(3u7aVypC6+gt`;X-?uAXyE`bt?Ac3WSRlMk(oAaM1>aTG((BC!hutjAX3wGcL~tXQ~F5-sH*6S)fs zEGJ!2mNSEYZgilhUv&Jl2q5VH9SJTM@@^MYx=16#?u^or(tX``yBc-T!E8WrTybbknG1e8(|8JT z=nFlJSk*13GCNCT;B}-AW^=1Faqh(w>V#90WX%I#9Memf@g5nNeM3)7yGuE1hDl$_ zGDVAHg5OX_qOBT*d>wbP9qCSFW3|pLUC?d6#|09=b$t-Yf5X+4>ZpzlCmE}Fj9r7$8F0(u(KS%qg7AbxHXr-}l}B zu%2ngU6&B^#2($`QQVg)*BhU}PB}@^ImxU*`q0Ppztc!&R4CQpsPI`?vhz^x&(l;$ zdOdPCt0oA=NT|q1tCpjJ-P(giy^B_FoW599O(Vr+tS-_b<+-p5Q{`WB&`@T_y943w z@KC*GT8gcCv+?l2b-&T+xb<6C8-31_a0Dy1!$D)PrL|zJzi8j_I`jG&@`K22om)eV zb(-Y`c+{%iZl`jsC8y}KD4N`PiAxVg7X@n%L9{o@{}f?)c}(!A&2w-M)gUGJDhl`> zC26*t-(WYj#}y;PHoRUK*1w_CjZW$Q0=|EG=#bM*zf2DU%V)_hFniutW_daaQa1izS(_t^Iq3 z^QCF^rkO?}AzsYs6j>N7Nz&g5)IJhYyu&c=J9a@1y1R)PK9{uz!i;miA4;{+laMl* zJR%%qyk0!9l7c{<5-TW|{CKE?2bHv)X-w>s=(sCTmaTV~1MAR5KBti|L+kso!U(6a zYo<@CvRb0Qu}^qwQqlMWgD*}OkDyecu0j(L-U2=?n1DsAxYk`G?^if}MQ$|j&2=)B zeTkC^QL=FYB)2xS9SM6$JZ9Z3C3T#%m0wJDOp5o9$Hq-~wP4png{2Yor`wV>^wzY@ z$Q$HzM74Y&%~_uV`G=P*#-0n7TePt|d7bWsUw!3t?4!6lwfWf|t8m;Z`sNIL5Co6L z6?*Rw7036VZ}dhT^}!HV(=PeiQv#zEQ?d%wbW$qF3iVu&kRoqMO%i*TSNA-b@ZV(qmW z$a_I%RfPc&*Yd6}B~%I-u=pouh^%1+EBeTLe2(x;Tsw& zWMp4FE>nm(#VW4BDv2boL?0PzSYj>cY4tnEQl|icPDBssw{Q0nEo?*mpYc*5%xbW> z;YC&zxmE^1ScM$7$wMgi#bh3j$aEQq)#lT<9}pJCNluz9td5|3c#6Zx8}4Sy-#=uN z)GGQaI0lRs>=(TmA}B5Io99OVHX7#{vgkLy;YNQ_-DyvS2BGtSNNN0rjw548{cd%h z>jiRdb|}uOnVg|^(Y~P(HMk=%UK`pZW@o?j06U6=%VSah7wO$voQC`JyPTZK)JMLw zEf4nQnYp%kM=)9~WWndS4Iw+``#A{LH5?o<8 zux)1zZdnoGxnvhUi+5J1_GMy(BxQq5=@wq(q97wo++rtN%f6TNVFk(s-5ypKs>8of z!sqKDwU(&@*2R|729??##myB8g$nO$Z_cj{#Z5pglx{1Gm#4K*&z54;Z+y`c#_`0& zBwPh-K*`p0fo4*!$aP!N9VaJpE&UiLknS|bXpeUOWZ%iY)#J>(m^f=fGv(ix#P=@` ze|{$_bWNH*7%<3h&5T3GA=h@iN0-9d_oy3rdu1wqBMyo3KW#Kp`DldEM5H4W*IJQ& z)fYFCZnAP5q1T~OqL^1hZ=jiR+{h_4idsa+lsSG~GvfMCZW5Dap}`IV1fr076eoWv zNibkK`c{jrWq0KZGPT-0i#|t4>GSCM{iJD|-4TC(M9V=JBtmuRkASFlCR*R+#@TqF zIW)dnTc^^~sbE;Vy5#1%WAvxIvm|Yvbl--KJ9#Qwl}D9IKmXx3H)W%~)2G6G%L8Ebvk=7w6D)-sbwqEJW*`r&Z;D{U4*59r(?*OXQ! zXbYtJ`d(Pk+8+G38*`Z$b*nc)T`3RmFC3MSJ@hG242&9$@nC!@U1(`V)9D}jml#Cz zQMuL0rd4a~W%oIqsUFObv5NO0U85w1J1E@LfeLu>;1Kd$u$dcN2Ah=df$M95e?@HV zj3tHHiwVhVIo`c`LGSMt{0pAwO*}`&ciS)GHmPq@g?p4>Sryu8Qo&34BFjUDs<&@J zq7yAMoWmwc@Ch99u_0rKm=k&eW#OfM(6*M4N2%pl6&`lUN80@W&j3ypJk~kMX^b4n zlFJOZ3)(W~EjRmW%10sSI@Yekz5IJk#*a{R5e6Y@+7trh;GbFN0-HN>wHR9-5)S;N zxzsbyC&8PRfrV9;3a16g3rDRZM9t}?-|yHU8EpYZtel#nIL zh0+n$;5d8u*HF%?zTG8RBa?Oy_w&;a1~vmy zEa}ataN(6dhu2nz!*^th8@MB3RP!6HCtV8MBsLU)o=*g6%RY0L((GI0?OK85 zQw;&Vx|^G}A_ditQu!+K0-9s81)pC@+E=8>SWRXVcaWo@45L-LL-O1sA!c>rQ0rO5 z;9!)37Q0{pD-$BZAvz;g8y*fNjxvd%I~<8~QtX-VL7Em)h!OeoW|ODM^iEA5726uuhOAqxe~b@Q++li_$uYc9#=onMCp#WDGraW^b+h{h z2U=v*?g$@(lNik1v=7DOvS63r<1#uPp~}2Z{I>hK&wZ&ra>)lT$<1H2-xsm>=gfUD zgx1wEQ~p=x7Ypk#+#iG>WVo3Rq&gg~{`r|C*}|42nH*uj(aJ~R)_pTvdrIY9{F#T) zvHMlKp4&ylOb(AQ!kCk`ESp*rM4*P3PNJ$!>7#pSoReyA%C_WsX_B^nTKA{)I0MAm zqSzJ2Y3*pvbq0v0*CN`(pM$=OPzbyYAA}0K^gVH_FT9hWn(I6P?yWf6VIN;w;jC50 z?j_V4_l75B(8^rv86Eav%unSEPf;gh+)k>|B5^Fxm*J&%soB)RI<1sq>*YZj`$+DN83?G4n@F$de^ z-{kX`Yr96uZci0owd5b{F%8wFKam@4KBJ7^iFV-wdn{zv>aX{<0+r*)OPqY*?=hw8 z*$KLJSalB=vgiv_)|DDvFe6D!#3*h>TU5QhRmd;=8DJUZ;&CW(hwR3h)KM?m3@VV; z|1uxk^Kj9LVKO|xo$F9YArwP}6^#(Xk&;$~+uiXr)wjGr&E6%AYS zCaHMi6zAFNn?__xrED~yNXJx#1BexM7O2Msi>5Ywel>`I*|beG%6$6MA-{)Zss+Dn z!4Dqi69)y8f=spf33a7d!aTm{0@i|ulfdAdZQaD3KT6ArL}sO2cUF_qBAV1j1GfnC zASE#@4VtAbTm(~?vCPuaJWWNCQO|Im4HuU6(X&J+4&AD+@aQ^Bp{k~E$4gXf^VPWM zgo=QIWDEvy`Sq?hZK3zg>4t|Bo)#UlOfPAXZoh2aLPi$x!zM_YxzdZXF|ht|i0-(rFnpOUB1E zlWuj1mn-pf2|gnBxDA9%?80_cuk2~|IEmmw!BwGOMHg@0Sbe4X2B{Q#N*xT*pmas# zFAV4TT2+KV9$y2g9Iglhq)8%huD51VIuet^n?!rah-iN|lKgt>rcNetEfB(vMh=(i z)g8eVLJ(B9r_AI%dTom(x!1W7YRpM*byedSjDz}S*j&tWm*Tdhua8|3*W3{*+vL6mOf6X zR6c#Lf|%ljok>jo&0(7Lt{z2w*S|!`bC1xrLSOp9(0JEbv>TQ7o2}k8CwJEh!~e;^ed_yLReyF#wT$Dn(^yIu#QWBfX5+@W;S6T+aMpeL;=x%kWq(RX{7v`K&|1 zcR(>=uF8@Qo!s#ox794S>*1{cvsjut{1H_39S>oY64GuUc9|;*h|%3S_oy&E-Ts5B zik6FDbJ@$7(Cq9LJa9{($we)=dMg!V>oi>PUygIJ_l%p2+4Nf#zVE``^Z8AGZz!P{ zgE}0PSoUdnE!S?3CshQ(MHCn0L3Ug^o-Z|xs?}lXAB+hl-=JrOpWS8 z$5&VkvVqOt9r`2DcO0x0+VIutw-21~!oW7Ee@fi>b{^qn0-C3C&vk8}2uRp}y|J1b zD5N(7#N@{5Y>*`0z;x6x#jC*UJd?2#zEh<;gexQI(ak6>AT(+?AkaoF15%dO(eq9Z zaBOeV?)O$~*KMauz=^^`redjzojLN0sP3W-VF<+W85o;cpL_F1jX?x}`h^9qB9F8A zOy;tbnw;5;BmiLhP!9ZRxQm3z&c3pS{r-Zeq|Z#1W%SMQF$?qtvitu2-5`5)JsEwq zU<$TY-&M#!zKFg|XNg$S9%A7Ur%f9-*AaV3Ir6EXn%0C~N@Y-!PLVPVnp?og(J(P# zNt0h-A3d=jlvp^iAM$%<0+vqe=3V^Ez7GJQ@7sR(TPgCNR2ax_Pkh|wUOHqRfV=i7 z85S+&aW|xOx3Z3Fjt1~}h$}so)GgDJo)w=)N?@-TF`)~c-9+2Ar5tS;bUDsq*(Y?R zUA`kCjkwGRCwn+_HO<-3|9;cjJ7RJTuv1(F9J2t8L>;{K@F^H%2qv=#gz}kV!IvD3 z(A}=+t!{n@+m=6_aW#(tDwKOV!f*yiLVi3rNoWsb4ImT^^A>*!k2Ey@o{(0tf*8~M7AL3kW6<@!RKDW_?>_+BYP{K8+- zv{%=UZPkCZC>3_V;iM5E$&xFeAi2u9Z8x6#u#wIzSZn&Lz25LDB$4xQYXiX}G1>>r zlmSEXCWbwuISO}x?f!P(Dd}5{{l@eA&}P>Unz;ZsGkP$Y+&1R*3x)KjjOVw3cW%@g z`UlZ(n4*CzykyYx0v@UMNRu)fek-+7vs+@ew(2S8q;Dn-*lQYKSmOl6$=czn4u_(op_gTdnF z`V0uvBy)*xFXN9rRoGY=zot3HsF2KCEj7_Whq{OdoD@Yj;9x&VcLFxXUE zQg^07BmRpgqmnKOsNgs654F*QIMP+;-yI(q)B{ctuY;$1N;uzUOn$v6^mvPMa~-av zCPBY^4ShuDXcH9K+IH}b?Mm<-s{L*j1_Kr0+o++%(rPfo#KENS@D+@8fl6^doqmU~ zWT9h2Fj>Nk)-`nk>9p# z4jD8_t-a{c=dR8uLf5+=Ymxmi*>w4~$-Eb{T9C%y>W)zSPn^%ceq=5Dodf2}&4FK~ zq*(nr-(%)2Gd_u~P)@5Uy#<6%mSv}t-i;3|qt)pMtucwmte-|d5FPBkqAj56vrt;& zpRSYx%6=e&u<0(VeInF8HYZdQ z_3qt7k9Ob5N!)5Zfz3q7nBKE=8XeKHH$iL<^N2;e$i!3iyDoCkhk#H;jc<3MicjYW zi;HyoZ2KP{pA6t2rPj(GC22V}4u@EPw%gZO++qDS_79+%-GA^aKsJOAr07S0c-$c% zRluv?s@RIXW$HdeJ$%V`F(Hd`y90mz+L_U3A^ zNIUliT<*{%Kw+dc$iEYUdz_Ord<@q(@IjV$kBxT8+q-#S~L62wa>_|igaY<=f*FbEBcedM)YR|JL^P(euf;$HHYNlsp|Kz}+$ zx}$Dh15VXvmZf#u2W?5;H?&u7$%Qz781s zm&KbW1dzdzA&1+ecd;?zz*RA8IP?v@ucx;+iov%1RSo`opb#S-m^Q;Q^kuy8Eb*Qv z&;8@P1Ma-uo%5q|2{M+M`p6q^Y8t%ylZxMSEjmlMPg~?DugLM#umR^wM6G-hCX4(q z;C5k36|l#}t9P)Rc_k$DN)tQC(7)RcLb`s+w>V<6A|+q_>Y5?lF~#{Rx*g;;$wx zmTE#zw%lZY9`YFPyE^H%W;ww!pD~q1bcdlb+Wq=|jHG|eYodHl1!XR=MOraP6&JQ> zoIFb8*d&79XcZkxi<_IN8YWRpsU>~3!(ZbwHtf65aE~d<(ez*!RxVJMI{WDs|I;(D z781#0Guhddv!_%L`>J87-0bEy{!K$Q&!YQp(!~zW^7Kx@hTWq$`_z(ue3$>>6t+@6 z@~oKOU^Ne&ULS;HKBapBkFL9$M#n-l6v$kL6(D&XXr@nkviqA&AFtq+vbt)qHNoD6zh6?lc8 z_NK7mbtkWM(SmqKZPTpN-ulKmJNj9Ge^)Ym#yCAbZ6k$F$nF$)!j-0C6aUTvh;BMZ z1)EPwKN-#;(xC;Q)Xr(aH(zYUz8dB3PFS?C(pUkQsIJSqKY&(nRJ>}Tt!2Vt>G~5O zvE4nxRms=?JW=7R>H0qXJK#*D-MLMwSWNP{dJk?Q%{#r5v_Mt!6QjqC<3muwe3 zw;S~ynrwj1Nx6=e+L7R7I{T*|{T))kMGi09ckPi#c`st?~B))mH311Sg}|B7?DiEqk4= zFG*jl9!N1zFkjp5;n9jvTn4%dtwig8UMHwqokaO%zZ~@N55J;SqUvWRSjA;ZcsGeM z*|r5_5_TaZmjHw`s<>Whcs5^`)Ozd)&X&!}>g=p5mn&eD-rw6Fx<0799jg?3BUVl#m|37>3|K5QfR1e#l zEkYg4uUdURF4%$5z?pl51Tb1p!_eNeQXu2>llcQX^L|$O;|FhlLVBkiyDP)f#j)VS z24TDoOOD-%lzWez#{8{7pF_i~c13w{aFQ>=J9FC|pH0>#m_+i481;1;vDc<-(OCIk zGRS#?>?64U%?8uRdML13{<9 zqPpG>I9o}QL9Ug?&F1A*hg7yCV)XtvPc(k(xhF9E@+Ip2C+XD6CS-Xo*c%I;i8z6T zIjx2E6SDTu5duM{&=7ey7zrsw-5wV@RFhurQCzPKEy#2I)xuhm7B*cL+xTZjl2cke zK>~cw>w`M*AZW)ncCz;I0h$Hx=MS+lFBaWjsp?#_J1ys^il&P=EFwktONZ)?_{gk& zly(l1~m;%VzOGC1P)3a zFZ`rj<8i~Y%iN4=Nnb&Nbfnrh7^MO08`eacj~7uJC2HfQ#uEBn(@L;w+}vMTIhHkRyI3#wpri3VbS zcGSs@rA6aEb|fq|4L&LL$YkoI<$lKp|C{bK_kR*I^{B~!$J3WG)Y~6hZnK~-rggNm z)GwPs%emyDOhuP*2&e+%28z*<*ITodhW*Amrf7W<7#;TwXhn5~8}fiy9Ig~p(ZugP z4J%ZOK7$xwQY#;A(g5;3F1kmY-31GjI2Ijmd8kK{5litpPGX&MEKs@xuau}(Yh;~p z`{j9x6N1}wz1&OuK{_UjRyEpFqH55q#4f-E7NEM?PAXlApXB3HGEq6%9qxcs`fhHk zzp==gt$i-wS$){oag0E;e8>Y&95~u(& zagZoBzW;~6?t?T>SceAdCZ3s**9xoho09()>TIQa=sE3X!YUN;$LsL|Tnl#}-J<fO1n=I5?+^Cs3tOS{y;WU#MP zV(AY=2`Oq0J%wxzsmB=nJ*D4tCs78^m`8zi&#dQ+L)>5k5=s;lh|OdVL{<^mC1nV8 z@W5IbI#fs=RMDS|ZO#8=xeZ92WpNnZ{8hU{S7O^?w+5%((Yr?l9^CNA%4F*VuD^N~R$ZuGcIaXYiWZ zpWVCsHraEF=-qzZo#%2QBy4-LH8W^ZGBpRqwLLUf*%}OYL?a0I?d9*)Y?rB~w%Q?d zG5;-iJ$p@ftMv1Z=4;z%{4inl7D)pg3moC&?EXn6vcSxpl4eon!f_0p@q;FvFF8rx zs8O-7w>N+O*aOC`Y{Ou9Jqfc^VX4p$xvW8`+oOyzS&)4F=10Ni*sjoIs?tWJN}yOL zNJ=u9_bXGx+gF}BazmB21NDhA6mDI|a`KBCi$S&PQ{w*Klz+Yry z0h^s@h2h<@6=U!yP7STESpv%dzTWM*zxPW_yr{!Qy`na9{n!L5b}_ci zCs-cH4a(H}Ia{kgD}Cn`(J!tB2!xzp_fNfcM*;F4a7ht?OW$PNk^Uy93a7%r2ZeTD z1b}6*$TUvdG%SqD@8xb?3u?H#v2u9=PAXRA&+cx@tK_K(j=@cDh;08xc>c|${_{rs zGYJE){lN)%=d=*NUvM5?htf#8?lSb`Q1JA97;ST^yPCFmgvshQr)z;hwcGA*jPZIl zl)=B%Ak6J@GpV^JE7$^0mxZBqEfbU|Hi^BvytMnu3>jI?zX}bzUlYngxE7h!felJ9 zFz3ARl$)=iunn;S6gSSi#(%{ChZI@W18f0t@-sI?Xfu!l-0U;b_S%#T8bUhMS@U*R zEuw1DI1S_j5`Q{myY&F=-aEK|^Lk3hJ79&tQlzWd@|I% zE3N@2Q62Rr9tqw~8v5K86!eh9%%aICn1gqi$EBOI#<2{YBNq+KPgkain?ftFTCy|$ zloomr;<4~qx9q?p$p0N6!CY%76^RCvU8@I1i>{3vNVj&6_58f_P}1%3a_^9rAZ}1@ zrTeY(R-*(Tw4UYQ@jjUs2zXCDmmYckOWL8pq*O#zs9KCMp;}S#mf>>sxw6dQ2&Ozi z)TOvIrkn;vft;4?3&2_>WqEsWY6@*3jILbI2b@v)V@7Lc6adD&zg>2}?_u+;drBh` z-oP7DOPe--lD?B|8hgmYB=^i&#Rz!=c5VJ4>xURVst^ItjJ=)70?U9reaCkhu2`Jg= zdx5D986TMlEpS8-+xh)Hj~p^c+yzn4=hKW3o%Aw$(rHeQD>j$sTnI0J4H$m(BL)|WIkgFzuYC;O+s}v_W_r^uUAWe>4oR9v@YYF z=H(p;U{0i8aB_~&%yh_W({=}U17WpNFGCWuld2HuVdl}>wpKLIjLzs8QEQ^Z2) zF|?E3s@`Zy{f62AF`~BozMn{vUMb=p_7lQ(LaK^MzKxN4A;!Ajab}32CpPG2<(^OcbS;u*3Hc>!V+IUg4Tjy^{I1IruAAWqGT3yh(uBuHwa$0gnw}Bsq zO_|bN?=3+1gbe$J^|EZerxGkkWb<8B$Jdgx!r#gOt`DnQc#tsU8W3PaGo(AK6h=;~ zS|M}isx69pLV7q2x2tX*y_z=&1Bp8C*2?`U(yW%=|GCpFT9}%$l$Td!(PVRR)3?|N zMIJN*3a*~0fDSc>DJ=o%(n`6pp4usQgYI^H6H&%ES%%`)(PT%0u#jh= zwJ$LEI;_`3{~q#N)1P=+B2FA?-JQZ9>`s}cdT+>V#;Ntf9RMi&H=B7}Nv0`k&T54D z^%be|kO#VufTYna8-ZF>Rqyf!T}i8`7h;>o4Ac89)Al_Z@YS1K2#^mg@zVHp{a#&5KSHssaHSswOKEzF&~n``47+L^^KK8b!Yi z3R}Ha?ji_0Ujf2*!S#p5trh-hB*uNXkWLb1FH9Cl5_epS_OQgLLfyk$)vwhR%Lw-7 zS0a#9iq5&Y^n!sxN&muG>5i)DoCXMKrQy{om*Gr!2N?NdG`nKgS_RlX`oTOCmI~#2yfgZIQWbH=Jve-jDD#fjB20-|E5($PEqXbfE?J!# z-xh9M`G@`<4gT*N@qf7{J;@0?OKjMmk&fXvStVb0NlDG9599y(uE zxAGs|)mP{alaef+#54vrCl;~|M{9&&Nl$+k&Z>GEw&_WF%i!j9iM1N6bT`x{KDvQ< zg2xqa-ohIz>yX5*T)Ngb{%jAIx*h4Q4AgH{r)(oV6SAyqMw$l_g<({r5*io3(S|NY zrn|qsaodB_#bDB)`9EQr^*1)K2?>d0O}NKGwHDz?G{Hfl@uWW20HpR%SM>2qn`w^A z*I#PBjJ+RnZL0*iXCAd0gI+#8JCa(*hi_#W*k>MT$n-xC-}-L+KT+UJ0KG@On~-)| z4o+Vs0gNFND$|D%lH0j*KoEE!s+EbdAyD)B%(PIi{qb>otq#V7TITQQ{VsPzs*)12 zxjwQ{d%<}(XHoi!O>p}s{<>hX=%2e;eU9RO+VIVRS!q;EOb|83-XP!@w%Z9p{a&41rM6 zpqtHAG<=2n{c8Udz`0Z}4{pKaVLWKhpzPa}6B#n&Zrf@E=Y4waSE^QUXMLA~e1g7= z#FerdmqeaTA?QBv^&EY@jI^v^Ho+Sqh}U`*n#>(knjU==O3K#*sXd7vNP4TN62##1 zBjcG{(%CnOwAVFKQ8t4Dw=eP&H04!FwP@r-&b=)0Qnk!)N1sG}5vwM`Ji<79WMv@gW~( zk^Mw9FMIV711i|}7))i{7Ex?OI*#s=Rmd-!Z=f|SR#Eq!F6%x23vJAKnVyC!D*@y| zYH;?~+UpTOtXdS9O^E%*UI!4S0m45$XtR(N+C%ps=?V~_Q(r$6!=)$j?FJgfBP27oO%;uyhuz3(JjYhk-BQo-8@{TD`>SIx!jQ6N!55X zm6Ghe4nzm7p}2p!x@4cJ)%Z)Fns6qtKon8rJ5NZLPwc#ZKrF=OuDpX_e>Z;{P!H1~iI zA;w1y^K;kqzs?(iohM!amN4a-T8iDBS}d0lkP!Gq1|WQ?rKRrlvEuABShVdYv^Ecd ziHL|(3Il1uV)OzZC*l2oYmz^@i^8q)S3>B@X1n*HCxta({0s+4r6+|=#MTI(2(R&R zr-UCr!ph!+KS8W(Mc>?J77M}4OW6$v6ElT8y9evff7F^8!V<7a_CBGxdisy!xGMsknDt9{{iPccJHR0hi<&d(!V;@xKG)vka#X<=3~^^lHXP zd1AD9__O=88^Fa$JlzZ!RhGBTBq045*RzhP50)ij%h~v0v2OKt7(2#|pGWi)b7S9g za@paJHeM=JOB+Id7Z%253xF$)>Mx~Qu=5Yv9ye@gJ6B6m_9X3EFFQ5C05|oxb5xOb zllmR)M^eezUTb-6Z((>~>4Fg`j*FD4(IuzL0Inttx2k8nGvbfPXiMh5AS~zrK6bb{ zwQ4#a+8Rwu{Oq_Eh~TLJ=gA7p7Ae=LnBlG9Pz&*TeI30QI?kX`Iz-^0=;n257_a?< zlrd6z6c#m8@nw1Cdpn%F%;)gFZzOX0^fv-ni@OS)J7}$u)s7GN2rb{J)M}G&&F34G zHCRtbyIuY4EacD?3D`=H%tCY~kJX3&y_tgpjs2(L{izzTM{#3v z!W^`9tEjASiI~@(>msN|b<@eB`~v41Y0-c*l+g}BIcol?O>9>3vIZ35lP+LNe zg;T&zpitEt-t56wJVzVNGh+xbTEu+MI%o>KHjGIp-8eBdq{9vnmegkM8Z>4`rLjPW z(2oJ`{HdleB{OB#-~E@UQ4D5Sl1fD2Ee+z;0jv(kfI%c@-Hi z`>EkkM`7ImC6NAKrj`H4VPpO3-TMdoZFE<^f(+|CQn=cpLXUy{wEsr-zoSh z$biQD{bVL-gH)q34yh3l^!0Z8?k^gKU+}W_luLiBoq&b$xoy?Fm4rl(=#r3+Cf&5jPzY#LsF3~$~ z2B7>ITmJy0DCXx~&lfo^Ub3jU>rVGZ%fRkIk+x4m@AdOoG{!9UZj9&8SJx-_78f&P zEBWC++H?F>)MuofhD5B>QHd;4U6;z(=0J`M|N9|_ZL>BB_YIxt;53x3fe$@6{BjrZ zDRgL;C~sZpI;cg9C3b8SQ&S|bug@kKe<+k?`AwV$lS$@pe2la z&TL#m2Q{;e@O%9edsC?^&AX%9KFX4K)L&X*-C1zc|42JJi&QF_W{i%}_dI{L^%G}YObxd! z){d_ZOPr2QU&KJtJ4Iq1egUmL-f`w+0_#SUci7B2dT-nk<Ap9&CB1&Eva91tMATY{T4#^0U_W(V66QnjTx^@eEDfsMK_V;6T*-E z1_|E>empWV0HCI6buW%j5rK~fh=Y2?H_G*3NDI$t?g$9FQ*xefM0xh}PB^nEDd>#l zt_}o{`RzWMv~-2k@Q&sA%20aHCW%`BAcc_#uzY0I?1maS*U-b#0BJG+U&mvzuuzTU zr1tK3<36*e697F?_}{*W8@HmXrM$HjLMNJ&?>7N-}Zuhnf=b%(_7} zPpKqCyWOvChbrB9EsxgL51*Gj=)|47dRzVHfc%oy#~h;jo=K=hKvH6Ah=TXcWT4~j zGz|&dz8XqQ?y(#B@?i0o2m}2u?B2^ymZ;kG=r7UXNtOQ|DIR+Q=wC~C7w^l2VIE4r z5|_gIj6wj2#|n%;K#d9|Zj{Vj!CjEgg;9M6H$ePevD#aGrRJUPMKdu#yeUd-jR%f_sThMMUj9R~8H(Pytxn2w9++B@S zpE0t}SdP5omNp)e45BEBKRHI(17y_sADiy7Wlm}41A_Q%)Ae7$RrPun#cgeu2ip^7 zYg-%IF;J4k4xXci-kb@!*t>mXeDSp*<;&8UWJ*z2I~39}^61CvuWX$T^N#X6ULi|LDJly${^u1yw|jZ)qwrP5j7C z*W{mSkxEZ1do|4pZ6u7Z{qIiqpC`MUPkh9qt$(s>Y1;=oH~q739Bt6!^Nkf%lbX?n zzUzKR54H|kNZ=$lOI)3NQ!&k<1?TU7?9gXD#LUcQjH}*dw zk=WaL!`4n_ec>6wmE3vPM$?b&8qL*E)fwKa*9XhuU>0mvxw`OB$5(3$TLEyWHZXCl zs*&dF4>_cGz_$E2)ra*42Np2Ec)i^jv*0iXDSXB~3gIPyEjC^rudXp3_b_A`dV??~ zd+v0Cln+No71pnIkQtEKx8iJf*%Oj+Dw>yHkL41z1gI01?4-JHM2@d%;i<~Rt0UmnhcnybaPC`!|||7kaOyp^o@dl21gNKL1&_m|fDt zxaYosv5qCzjZeis_?K_V#i^Z#7kvWbGru(b5Vy@!;17%a5KLsYa?tC;7RbbMx;+u= zY`4SInQR!CX2Y&sK}%~B)A<~DHqEB+^fywR7jGUJN>?#Lp3#i}2G&^KVht&4>qm+F z2xF+0A1xy4g0)RF($!-J@$F7G$Wd0Lc+In3 zKAO+X`w$0`Vhfq6l%q_WsUY=~Z#c17RIkiaw0ez3cct+`W5T(r5oauG!S` zfG$f-g{)26t<%gB4+xo++bXTKDK7JvveGoAR0L01YM$t@QWHUQ%}Pp$OwDsDdNvXPleC@F#D=9`_O7D{@OTWeGtxK$GL;=v0k?=B&gA+O z)cQ=ss|jeKQxs5scdm|prHaQ=dQI(3`?b+ zH`het`j8(HTi1rwR~9_t!xm!_C5XWUVkN_W{E64ZYL#YX3?GJpV&@15)+lYKP!x$AwFg5ksbjK8=%VH{{)#u|X(BV|N%7zm zmFb9U>$FUA{d|0vxufU#ozh0IGru>@JEa;V96drlN;v2%U|QI)Q66N`Q`(?!)tUp# z9xOk*2G1|RkRo?8Edp)4aC!wivWZEyY5$&8a^th!-goz!SBUbdY}Db`$6*J*loESR zwmYw~QDYs4E%ocii&N`{Q#ff3XQtH>dBT)rJ#ik_bgO3+E1EYK%nEj2ZloI_!A62` zi4l@$yd?%zGCJjQ+hW)3^i7Q9Gl=G`^<_ak-blwa&mfjP5-u;^#N*B`7S7^g7X1`; z4Gqh05egclCt4s_-Z59XT9}B9ksxB@V&~U_In%3y+%>hDwdJ)X-UTjX{Ym`3x54pSae?Ex+c|48Fn|#35;331x9@YiY)bh+C zw+Xxdtx~&F^L&1!O=jbq>MLTe(p6{uSHGqthz*?`SL()X9Wc?5g67X##K#&0oNz2l z_RKuz4o5Q*S*kc!yg-{4ojbSiyB8jhB{(|9Ei!*9lpFFob(bz!NzsIRyhTU8l>f5|}H# zuwRt#Mrd(aS(&J1Ob#hp?^12R;Q)N0MgcZHE7-j$f1}h#CMF}`L`HNUEzk`=!5Dnl;Iu|MKKf#zc{jGU*lnz;|1Z?f&)-Sr_Jd6IN!G;<;;)5E*3&hz$_vk zh6~djJ%foO-(OZSch#7OhrMgn6G24>wR4Xr#VYG-Wu_i}nfga%cFu4#V zZ*aD{N{hob!a=1&K@gg?#QAjSLp#3(A8Gm^Y~nTkhJKyCO*fPjeVNlW$@s?70;3y5 zMrEO*+K&2-P<9QzTfM|2Z5%jGDY*Lc%=KdXS6YwV(n$3j9o78{%}0EVqCZ#D56t1o z(Fsw3YD(BZ;khuVQKL>O{9$>ay;Vz{#Jla9|E@|5Ii<6*?1sMc$TtKGhj&zaDpc&- zqZg>xAW2*hCH!5N8)C9g?ubNx$M(@*A0TC`oWQ(h;Vc3l6XqV$6{B0$)fkHB96pZDm+>Q$4;YtFTM7G)GUq>d*m|o3y=K!iKM)V z_|#pWB=}ru>c~HMAV{*k@A!{D?CDR}`V>ma4m$ig#s^P>zRD0KcdrP#AesbnMG=>cD(}Ynnk&Ih~piu1N`NSdIUE zu@(f7W4&vsy%LP_oqsOZj9M~jsVp%#W{JB3eevy@47%1f16^Y!Mj?Ln-1TRR1sNnO z8u0JduB4TbR$63-hHHY7#@dfwFZ{cmcqG|^cX$)m#Di6yKx;1+IfXF|{R569W%6e* zL{erkh}eU|?;#gwf1ilUdgl(ll-_JHZfXq_9MqUY;?=rb=bN+k2(*%%x>I%|&6cWN zo&{uxJDZT=Pf^a|$Rk;_7|$u%JvToA?N?=^Tny)QOc=B)Ek&|;7rolD&m{-A z0i<^+WT8T})4vq6(p7?f)9f>NBL%{SLQrSx9TL+S)pLakK4G+En`3C!^l%zuN2X#J zW#u`0F08U{aoXtH5a$=w+p6Dq--bTyaH#W`z4pCHBt2*Pks6YX_^MgOy1!$JyGJ8y zz1IJ;bN;g;Ts*1nV+d?yl`B0BH$$*0?O)-M-VlTx0*Zpp=LK>v`o6(W@1-$iov zx6Lu`*O%~(G;=qPb+ME*}^=k^&pX4>!9N2ZE1V>_t3_IG=Z7?VjlMWX|7^RY0dRc z`L6w~#lV|}8 z^RPTGh1P7=GQpctFr?@k~8qLPvF z1@xW!?K9OdK-(Wo3n!sv-?5)Wt88@&1!uCw{6XS zkhXvNEsQf(yVYqHl)|DF2jyKc6Vc9nihgl2vqOs-Q`AgPol?4MfF6RT_~Ubo(ecs@ zDtSUw0Z|}TSnZrNF`)3vM4HB)-%<8|9P-A)e?Vks;G0<7!bR}|>n{&SK2FHB z^ZvMVt!u9{gdObTwTZo~&mbl|!=zk@7$(cK_${96unx)aMGfNc9W*uVYZSgWmI+H? z5&0`!yEJ2E{Rl^<%ydG;Cl4YokbOFohf*$vuxP7KyUlY06%OFSxaCXI1I~3FHlxiU zU-ESywhOP=c}Bf&#^GJ-Bp$wkJcgVjY~wiSORn$NhDck^8TE-<5Ajboun zKMb&-QX;jtyLJQ$^{{F+$`=Ii!osDRm>Vg`h4&1pQmdRZr=sn+a(ztg7p=PcAk-od zvH)RKPsoawJ@uwXr3pw0DYVzxQPI|U7%X9j9PU``Jyn++j1BJIeMxX#aJuRH#D&K8 zf7}}T;Gkz7^Iw~t>Em$+pmzu9Jr|OKE0{TrJX1tum+ z>8AqxUY4@6?8bR%`bR`_2vDw^lpN z%yeTYb@<$_69r)nJc|>fPJ)~)R4nm1mlxj)A}E$yRs)M~dTm>4{Y|O;8RX>kKP%v$ zt!ik)me~0xHabxS%6A1vXRj#Vy%`%L&h+!W7qj*YTLKBQy727mf9(1H>~a4#kzd?# zap{Rj^{!~&GBBLBN5B!_TZq%d#Wyk&ySGXj5&oDEAMMmRf-`Gu*976qi*H(N%c56$ z#Xj|p)376~)!Nwex}O09E( z9xEraT8Y?-g1Zc3uuOOii)g6S;%qZfH7DK+L8W@=fa6gSnigUunSJgaMlYzWo^77v zOjBZm`;Na(D~waG`xI|2>A_E%vVEk*)T5i~{i_;aL&CFkErYtfH3nIzg zMW6*=w&CMN4RD2s}p0sh9` zwU8d0#%D5U(~MdWUBxjsJWG1}1ANrj{B;s&^HS-mg-30bUZYg??#)PrQhUmhmgCXk zpFWByYIHr6H2a_dYd82))Vb-!-dcG zdS1QLtE})g>Atuv-~~uL&T?G7`PM;cMK{Xf$B_=@vZXnyYMFB&pX~0u)SW$jH|?H! z9fdSKF`cRCha{+%VZ3#xcv8?U6NA40v*%dy{aSPJaH@fY&MZ0znxfIx&geLLZEioygsKl67L!E5m?7 zF|bGN<-vt$+PfoU*MHEdQ_bfSmK)d3s#w;(pA1`xkeoFxzkg+XswuB&=LdyW-Nyjn z-97=466BAjxdRQWM%LEBq9S;bPu!NzGym&x|F@Grr=!bBWI6f5=325J#3+jD5%BH) z80kR4h(mnHCpyF>)NIB~t*wo$!vbqX>|@x0nlB!C-D<1QeEiTB6glo1gEMT;_%SBJ za!EJDSon#bI4EYfn_pmW!P~0h_m>Dy@c5`&{xPsZ613kudREyakbqrSxb)QE($mP@ zhPN&@UTxZRs~}74gR4Kck`>&_l2HeuhVT!~Rb8wPg>^INr@ui~Q_vw};HnPW7X=2( z!;#P6fQH4e_Y}Of#$4wI;TVp?`PrC+ur)t9~&Lb)Xg*z$p# zTIf0p=PCjU>qEb1GmxJRQ_OOoTDPHYsY!raxK8i-w7LtTfn*YbBIkdWJ zj=_W}+Yq`0C2M3xDj0E9-f|xmVW~Jt+G)PC^m|yqKp$ zm!MtlQCDe>rsslM>E8qdQ29qLbjPxqFI5#gY;)GpL2oI`Ss6V*4h=63K$n+`h}ozI zOxV6F*7|XaWVUG<)-&uiq1icp2R+sfQYL{iL~8K&Z621nmsf`k`~z-`?NhNVDeT!2 zQ=2g*-8BE|Pv+oX@L%0WZv(EVGEqF4dGvJsuSUot;|137=gtkPNt8!_E7<*U*flL( zsR4O&79a8DYHP+azlo9g={A1dJA4SRZBa6~t=0G@gQ_71tS3{wOyzSJY4#fEerJHT zCy|AUy^5TtqI%Md)h*z@^k**_zd#(wcyK<8({+lpN~uQe4+(=R2u6ie@=Vw1loe@_ ziP0->Biqev6szvXpu-ak4yJIq+iQ87JrKPnI}P%JT!mkU+~k>21hy~wh_?5wMg5iz zx-JuGg$f)`Of(P_s3h))q^EL9QC?x|H9Tb}KpY=LxzE4nbHH(K5yq17oup#%x8`a(jvXe`}qx&q(3Qvf7^cv->HW| z^l}o1xi2pTojVH9@FG#0vWn$8UnSb0;=Iw_Vsd}9Pxst7sxX}qKAxqEKSF1^V-oF;;FbVC(&A5k&zF=W` z-96Vr$#b+>rKF2wVV{6_rImMVt@?Vk^6-$`mMdq2Pq@Bmxv>RewZPFubL=IZK`cTS z+Kjk0Q2@N(k~D!=b9tj1>PIGY9=Ak^kqq#gvLHM%t!^;|R6SlvEo#<>SS?QIil1#q zIma9LWAym%d=pcG^9fVXGUAl=t6-?_{SSLq{EoTN0_!Z$-dORZq>uQ5UJl36P|%HF2K2=e>L?5f`&ngWI;L=IgJR#5=FV z0E~jVXhx^*tva`{uwop>>0oW%9r%gE3$+@@_yy=-K_y~JrTzWW@g|UoNP1N(GB|=e z>YC+N4soEA*yg&L6Y3}|jJ;9wd3fOTQ71boorV}NLcRcy)%jARk`6}zvePY)o&cA1 z+2rmQ9}co{8&;0oQxtfVTYo8iREmJZVaPSryXK6D@m^3rSwZlh?9BZrSa4wDx`1>r zMFG6m991t}o^j>HaE!GmFsJ^!tp|*|hdL~;Sg`s8%~RmS6&+$P{~*J5O|#Jd6pIL( zqDQx<6yn%B?i#0G=J3*r&>mLeK-ctO-=yywr~}gOyvx!nIWI@e*e~VVOYy7pAh%jI zL76Q`B$Rj|_`B}brb`u*6CSsXAA#I5i}N&e(z16B>R4QX=%;Msh{i1Sc&Sr+D9I*% zfmb6m%MMzi1cF_c6mM>4_81gbjW~f)fJX$m`u!1LQ_j?)pUJM<<>e~R!gegsrquNPh?3$q(2zQ(3nFpCuq&jC#hc$-NKx8>C_Wt1nekAHCPRR40c9#Oy`Wum0sJvWac;$w5T z{i8coA)ZW*=y1omN*J#?Xk{owI&qvA*-YNO9ju&HcU^NsgJY5r%T?pH=e#65iBL(fx5l(LKA zDaM0Em@ZMuI63}lF-gG-nxPJ~)Xx>0jerZB_nh6!RZEzt^^&G99(m$GwABwZnVxv` zwYKNRLQSAJ7>|XPH#9vv=Dt5N=5cL%c|;sFjLRCG1NU{|!N-)3YFgGT14+ax_DyAb;OMZ7>f zE6j+|?0-E@;oa3~fsMMMVT5hz7d}BO2Dyj%%66{(s7b-)b;_0R^1pU6?9&D(Nx1g~l-&{g;jXg7K7v?YLh&T8eh%R9cHFd&H5I*Yh@+XnvzdQqjm z=f;8rbWW%JT0kQJ6K;2G*w(C8c>Ls5g(aujB|&F&=wMhDO*GMo`ZD6~RuiBg973qM zygm$JH!+hm5IY1V&G@Y*tD`~X*|u?s_M?q z;nxb~yASL?Zo>|ZZUo2}ygtY>p}1+Rk_hpr07x&%ZEmxV|2hJjAerd1*tTVjQ(0GB zKbwfPBiX*n4+XFK&uRkoclx%U3my{aj@r-xOyn)_xd7I+q0Ahg?na1FTuW?-LF^XI zdNvh>-h0%)p0`41!7zQSG$|loE=#~*g2QkYqP?ja`I>mTonn12sWuA-Noli z6)M((wVhX8*1Z$|$yZnH-srwx=NZJmH(U8`Ztnf6`Ede*J>8P{!|W1N8v zdQuKS#dA&<#LgBdst^8F(?&4%yHzF@cHU%|c@G4k@H%+PecQXvI!Z|Zj5;8Zq#e>s z(8gT!bi=DhuXI_+Dfcq_+4?&jTVdjiLfZ)MVz-fTWGGX`qB&R`DM{#T%{Okj2l8V| zUEx=4Bm5n@l-k9oZvy?wqkd^+#ubHX=L(9F zmK#PS?=*xRI*OhHxdQIWIi9#cm@XVP7~vzaJI3jgs(`4vz-#)cwZU65pI61Z>&YLu zH;w;bT^c_zUFY^@XQuD`YHc+wJC(TnXrNd2SpeWikwU_xM|vJ0$RD>m?M;)-xwS8x z^Xlc*7XYHb$nRJ~)FgdVO=98{fB;T6%kv{e1ZUc2AJ{uqD^03-cLzb#MfdIFgr}In zYGw~?cEpJSTE{J~R;NxCIWe=XS&A(l5JFo(y!1UinkHZvIysmmH65|M;(M~R0p&S$ z>KziN6DF+a#9kP0RujR>Cni5BlvhJTjI$tpiyAI5TeiFXcz&=%92S7ni^x+AQ%B(5 zblS*cceQK}(hA>@m;Q!w({0U=01elSWFO)a9npvhDy!}W>0a#;Fo*2v*sG2-yu@2~-hfZ66;{I$z_~XR%v8MN`g@z@G9s>wMZa6ScKP0a1q1%e2O_#L z!6NG%fHl;ltjHs30XQJLrdR1U;suC^-#-1gS>Yn!riweY8G}(@?P=x4a5I~Mxr;d$ zAF{r%G|B5)H-3@&as*5ZjE?GcJ8om!b=r|99Objrtr$6g)DijQR5y(k!h<0uTj({nQZx!G__o-4J>1I=Ul_ejg-Ei4^HhrA`UyT0eE9RzBpEOC z;R`uE^2o$t6HG^Pw&Q4%n^AP?DV^oURM4xzJWT5mV}%jkTK}LGHXv!t<|l#Lx-CGH zQu~!W_}Q99C~R)NB|F&RsNRQ#^~a6UhRG0x(QyO+VU_FFwF~p#e%7Z}u!}e4cZvGE z?c;WDdSkMZ^*(!}wbP2st&r|T249mhC$VSsJEhx{Pv~CStnv@J7`6(-CqeXCLO`}l z)v!$MK}B);vU*wrSLd@ zdOXN)Jn(a{LKx~H*Aj2TmrE$71l>R~YZbOkcn9kTt(l(SIwwrLZaNPa`fQG4jmzfV zc&i~WMFrU4a;ERx=d4ZK#;6NF`>px^dgsDOxWd1K9hUgN`V&wht<;lG#TPM@G)O!9 zS4P^8el1KiZB?uR>}$mRkCO_(J2x!zU%W$r5*`CWwxr~Dv|8V=*NR9*Sph(53B%+% zTSPC^dw;Slx;Bu!RUAoY(crKKJaS9TQa4Xp3_}|b7S|bIiCUytug2&Z&zf<*KK9nE!iLpCTNHj{ zd$0)=e$RIAaz}L3ZuX*T+ZShp=H4+ghInt(QK6mHUAI}p>tiEih{K99etMW#3*~w1 z@*XjY+6Wqu>2Xp#8Nr`N?Bms%3b6 z7;f)H!EcfWUnZW{q!6<42g2(Y#vWiMb3taFYaztHqiwx#xxEEv9sjuYPw;POwQl8F z!HgDGD|<=RU3aO&)9W=$hcXR#8QJA@(dT$7r@EubxRDzFPNhoWGcUjax#{ z-e_U>D!=YpTY&DuK4&Pta9k9?3a*8=dMh~L%hh&{t+;NNIo?iveHBwSq%Y+-!c%a1 zvC5i>PMDu){>J#S&PvB4BHUn~4Jc00(f&9=x+}LH&2o*e@{)G1^#iliPtAYMQihdv z8B<}k8RtbRj{j|@N=l3o2Q*G4-zf7)3_Kg0G&c4iCK7OP)$~o2Q;09P_ zCr?;OL@sA;U1a5R*Jkl7L;qoKoa({YXp-~Du_n>4IAy=Lw2^kAsXh}%V}T2+UuSk; zdP8IObE(#-F!g$2zOMfR?cBPO#V@~Pzm3SVqw*d2{npDt#ZLp{#TQv@)J(Fo<23!f zfb0e(F+>+Vgu1-N(n*$hdtpbPl*2IFbBi-V-j}TnQD#B+cBeshMhDJ8!@+PHs9g)( zz6J{ZQFi-n4}qP(3=S`_wpgW~A`$2mMk+G5N26v{mY3FJ%n(V72LZyH_M3jath1u6 z{aOx`LI?p|ZG1-IlQj)N8`O^zKE>W*o%7eC%g}cX_9Ii~r0paF!gP3o=;+a=|G%1Z z9V`Q_*{IKn8b*JZb1@)kfVGQc%$zk7gs!?8OPq``>ANs%=qGKV-ioLXF@n>k zWAWu;E#af1374dHFVe7$?%KHVeqPn&^l2lDzyZZ17PZj56M_|QL1|qkb_Q!P`J0nt zwrtjDr}GV@j5wo`ht1pV4#2M-=}ei9_0YCzkrM_YQblPAD?2(mzi~gm$M_18o2(-^ zrC&guX>$_5H1h02d2aD&RwM)*H=Df`GV-uFBPY{9B9xrsV`e~o<-i2wMt_M*y4F@j z6E%3b&;R;xV7@^;;KpC{q|M6kH%>+*_1dUO`EPg2;fn6Nv*UmhhF@7*Nvxti=YDK| zKc_x7q742X(JCH-b+5D69kYkmomT8QMMqWa3ld*;&dr5k6~)aH*36M>ATgSF&mQ&`xlnoiyWkQ2}qVU#SI1bvL1iHQC$=P17)_EIbf+3 zyjNXfk0cjlF5WKVeK05dl~|~sqQpw!g7FW^!TWjv+eI|j@5hTwB@I@uZD^xd_7s*j z`(`s1rHjlr+L3w(CC!c`DjQuHv=39?k9)e-R}hlu83BTc5uj3?e>z|@pUdv^pE0Nd z=Yw3`60X`V)uk8LFFh}74o|p5xL(2L)SH*qj|Y72?mKmT7ic7Y+JnFH^_zi>0AW2v zG|1T1Uley~!+|udfD^6=;b=vG*Ge_;N|ARY@$D^6N}Mf09ziv|N!Rx*xWrGlM4HY# zVSQt@(WtsJ$Rw=(%(dDHU9XXjX0Tt>3BQ8H$2mxBBV*ad9F^wPv9u&o-4<02@izqh za$>Hh74!?NEh5hZRTn0{^B8Lv(&etYiON=Q8ovPh+&F;o;nTfwksSTp~_UKVP^`0bV0vD(&&LVgj7C zfQ~$pXEW5{H6auYhsLpE=&iOZ6J5i=pva>*?Y^Sb#khx^hHD#9yIoH98|ZsqOJRxh}|6GM`rJeW;PS; zSDvtLq)T$dCZsfh-FJKWl+^gPWH^O-i(y+)3y|w+S|)*6b=w*8YMaJ+19!nXRy}(L zz^bdzj;Ab*-@W$#x&HwFrEo327BFD=C`Qfc=9{?yUFGMSG4h?_Z@F3?>w|m@t-q1Y z#Kt8^3eK!&OVGduw%yYvdsUTzR42s zuaToe^$!vJH;E5HlIsP_JGa^BTkL&jKJH`FRZTDMW}g34s+WI(SJm6)o#(7S6c!Z* zHHky3U$M7pg%Knu{2+3Hej}|8af3R*oOn{+utY8<(w5R~%%cw>q#TEW0wM>?PF;;v zZ{7Y>HWC#7t~ie6Tuc%qB-AF4oh00CNDe+mcfm;fEEROmgdaXQ|1cq-HGMNy=7Fdv zu3P%8{iv=Vn6!nE&DtctrgxP3agnFSHubOuWF+jtsDx z2`Z;aA<8IJ-bUoPEd-Yn4Xj#SwuL@4&&{CoMKSg;8Zl~D`Zj1=;m|$XOdIaJ% z%c>=h?i;i%!-lC_)K9c^_Ic|Box!}-ST+J2=aI&DL6oqFZ>pWa$EscA!BLOBPJS6m z`Jg%JB>yR(EHElPwgSMk{pjp{zptnt@2+TkRL`$l85f_Pt=tB5DC-?>jgW(e^?<`l zS(C43@bco0lshO9l^V$F#Y#0xcW`trjoYXuw!|*LxCjANw=}OHe}iN~M?fou*Xek; z13o98bP1<~7nTK|YD>QOi!+S{_P&$}P<6%cqlQv)UTQw#FgW#YjH1nUE7?@~iD`GhBX!F8D;fau!QBff0smefuOw~VQ}IQ{DM`)WAx603L9hq0A#PIcQW;2FTg~G) z`T5+OS!UV*Nj&UEMPZCezVpT1SDjh!0eTcCh4Jy=fW~J2YF8v3q9o=4yjoAd5>0gXmD1FvCWCWKA$Fk-_ycD`^q*62y#5X#-WkKOO?m|ysJ#E9dF5jB<29f5gsw@C zaI5);m39_^^(^AL3(%tENbzY8AMWO-@)9*)&zqJXh)_OfH!LT{0FM8edg_AR({L5b zngM;^ILx`h_K5mD@G9BNJhbBPG$hKJZ=9m2&CbB~aqUZ)gLqw~J_h*MjRCbI?DmC3^<{aK!KK*32J%hKD7#60k55Cs2pX#D+wX; zVFwm2j*f(xERG&XyMcn2Re}OJr~I_1Qm0NpAoDwByhVrmZ~Gx6>`FWNV*1yEB{0XK zprDz^{L6Y2%cU!`(L z(SlI(cVt`rNEx#I@r*F^lv_3`1JD{Z%1S&-{{k%`1r-?Yf`dWY6|>T=6|bQhE_aX^GBb% z{c$tDPO?gJdqg%6L@4d`0^RdT5HE>ttn|+R$*llUSX*Ayo~wKz#tP!X4@*ulBYIcx z0Au!i&pEzLoRr^s3ZPj;!4X=E6O(VfRfH1{gEgxuKx(doHMsixoO!CFkMxR`i(7(~ zoRM3%j@jXkt%MeT)c2gAMdCsQVwyaa8xF_gnHs8 z3!LFT^sMOsrBwSc+0BBjg_pY%SJz#as>hF@Dz`Q4%~12LqV}ZN>n_f;vg!blk9^d~>az!6q*dDQ*cddQnqFMS%mIA=w5TK&NU(e| zX9*W?+RW-hORKTc4y7G4*IgLbNV!Y)wzw;E6HeG5WWHJ>qxz}?6R?z5z$1nEpHQTn z@Plw+x9h~6SlpxX1fYA3KLdra&widt$N&b4hu4QPktACO-4KIX1e22$^guPfXz>~I z1aN1x9C#mvnL}Vy#vlRhlEVD}BU6R!~xKg>w$1Em+hj>`fFZE#1#8}H4fA5Ep=tQ7+^ z(Jwz84QS6YBC*TWNS$C9M0<#5F~jTZEsGzdGlN>}=0C z0r9gskDf%lP)n4s2?9aHY|FsOOZB%^qMufuWPY~z3tbw2zabkFbTMr^ls!qr+4e5J=AOmM&`np`gw#(Bxa2 zobMr?;y$%iVDcR9aYykI%glMPTet4>0?{?MeSoMA4ZQ-?e(PA-0uYT|n^~1`V=-T3 z{!L?G<0^JgG?Hu{ZdoT#lPE-h*hrfl)MHKBS|rVNAh2GS_=VS-P`eU#CfyeDlGl#(JXC`XYQyj0`2*oVNR6w5{L}V90-%}x!V8PX{ls%d%}ep+9wib(x!9>7@!U5rLOKjAyI?|~>kP_OC!t}9Wqb|bXn^Z;!ctmd=!y^tjY$8TS&taSki}`jvlSE0cdK244|;ODsEj~+tF#TuliE_*YMl0hYb`mcl!tG ziR|Q#M(dm^XZW_*%c24g#C}yI^LOVZX7Yk`cIj^j|FNRR={{h~j{NomXlj{vF6o-` zEfl>qD@m-$gv}j;NAuN?R7{90#Zc**vz=!Uh6w=*Gi8L(AG5~2f5E=Gno$~#nU zc$p%q+gh(7qQ^I-4`=y86hNkEL1x-*zRejMG>Mm!)osR`(=uyY9My^eFOZW(;Gjc} zTy`4Lfc^x?VMX8CMd;b|wULFL=VpyeXXyD7Iu`s(vsNc{A~`9q0C{=TTrKbnT0;v+ zKxZ$8!7MJ17wh7x-_)Qgv>p0sfv)4mGm|PdblMW~NrOWUVy??QA+VY(1_8=Qie;&x zzu`2QSjGGPyGoB6`u}D8SE&PRYkofO=f59p+`E^Hn>>0{41f4HZI-PWz`!3Wvi9r; zvH`w7QS4{y688O`uwMic_8yImpRjsqQAdy_yN8!>);OID+Gxr=4&J=01$aGf8GQ5r zQY6}Yx5wE|@j4)W;Wdt)LzFM1bvl>X1l3IP`zNx3FXIQdk5;Npb99*R^G;IW*qOsd z76%b@rl7yH{(WWR638TEKm>*u1$ykwG=?UhApwRrf^PhEen{JO^@9kZkZ(j&R+(O?Ged`^ZA${W%$9o6`5hhAO7FQbT>7PRTdeOs-spng; zSfjoHK&z&=41^!+ANavJ5;{-Ju8A9iuU-3u{9*2LuH>Nqa?!;VjWzZIqob!^0?sPD zhc=)f0FcXKw%%quAyKJ%!R(ulGFJ_m?rgOF$7sL;kQu6sUjoSTf-|pc0B_*G!UFWx zX;CdgA4{a6=0;=jCVe6$jrtCQAr@IFAsr>12r+V;zu|!pX4K8~BO(HuSaP{8<1lzd zC(K8-i_=?%s_+tbI#c++9q~=OIPNoUFz%`l&-=RxdyJ>ZrG>WDPw=ZgO`>Jp@W!)p z*6|K4bv492ozE;%wqG$zCCDxoGjj5p>5n47*zqi)t%xi;o#q_9d?*p7ekBLF95@yh z9_UcOaFizbnqXTTg>?|z>-`PcpP1CkE>^qY^KyIa1(VH6?IrdNQn`_3`{;Lo8{oS{ zU8@?=ryr&%XH)?F9v6VS(X?*3eDVTdtiqR++Q**wC71#)gbBHxah{PT_Jc&hO>S|-)O~b;vq5N zeom3H9iydifNVkSH)koF4g|&vwBNeSRcc4id#CiknEx0$dSMn+w}1VnuSwrW!##rCJB?lY@=V>h@-MISm*Dv)3WJZ__h5Kv)SV$3CQ4-fkI!{wCz&;^NOyJ)9LH z(QuO-NX0rN*s>CaLZ13sm zB2`p~t`BC=7vi}n<_srz#%mEH5s9x(WVokpCIen9&}l{d&8Ak@*r&u2Z{67P+E6>tB8 zW~)z&8ckVf<&)74wIaxn%i za2F zrd=zRZm9UR)B(XEu{SAh;_Nx&dbB3|eb#UmQ2{;PMmF2YUl0t!z#4y0?f(LT97giYhd-UfIXlo zmf{+0Rbc`T%@OpP=BpbieXePFnF`|+79rCfwb^(#)jCiY_r^x!fK_N`q-%WMle|z0 zgJduDq4!!ukL%c7+1`7v#5_jZ|(xle9%)@$>#XayEE;SU2o-p=X$8qD~sV;$b=1WU2b$b%;I| z7t&`BRz2D+U}c2+_TEnM;c#}1heRl_N^VQkBI>#s^Dy-6nUQ(%A7I*&C zmad!}LN^I(#OTyF3T${PJI(MRcBah=QI@N|Y?OPl^Q!ENnKNCtNlTwB?^ms>18$~U z00>3;5=aGr2E?=5CcznY;>T+EZ0y-hl`x8%;p7Bl>25pI;%k&Y? zsbNt%KA3RQ%I3Hg9kk;Xe|VV8RGJLJT5a^ZG0z<;hH$GPCP_Xe>E zpMNX?_rzwoq}jbz^2GML+5EMkEKWhfsH+gg=4B2TtPJk5=N|tthn`blrd?>Kp_ElX zo#TKr3XbmJY`ltyq-*H;C4Lozm6>)(u2VtMbkVB=ZdOx6ym<5xJd$fL!!qy;9ZBna zsY!{22)E*@bOJ@CVE9BA2HckdinGR{AlTr~xe`Ef0bDJ68l&!cIZZ=iz1RMmt>xn5 zS(@a*`0ZYT@U^X5$atwpzA{YV>%WA`fzfPe!#vP*Y@V;GXJwBr^>UFxl z7|-_-5-{zXoj-*#en5kfhE@gmvc*s<=I9PKP8Rh7GH*)2sI*^KMH0Cgz+`}(@8rio z9GyZ7y4i{5~bz$ea>gVh~+l-i|D<0q)bKNsVQ$3fVebUBy&T)0oAOa}z-Tbuo5%#N!7=pPXc7os5lMtZ zTh^Rl_F`tV=f)arAUOijp~=C&D0b}r8F7{w3db_swdGB}#D`VZJKXLg0zc4f6{cj< zR^|8J-H99ABIviUQJ4RIy;G4==Piz^=yF7)QHw|6o^&@D@90V-O*+!4%LBRj;j&N< zwqc&MpAQe(m;~9ooCjF`&-y-!fG@P1H&5-CbvUk2^KaWmujnkKM~BHv_+hh}3>^gH zy^0Og9lCB-gMfaqTNE`b{Eiz;(qJ=6^pl zQk`H$tUysV4rk%*){Ut~`-Xet)xLc*oC&h9Lz#B$|4wZnG8~7QA;rpvj%f>M?*QlI z8DP|Hn^e-Y3)Ef6a8x)0s^CjH0Ca-N0cy$?0#D~-4trQnbhGMgc>XJ#dO!7-1#j#R zo)Uu#Q5w9G*yeryuCn2j@SHA&kty3C^x~GrLswI?VRF_`ZDde7&CGGJJAc^)A3t+# zrF*o~oYT7{h*+J7eRTvu*FljcIJ>&@RS zEGuhPt;ugk|0@{iQ;REMT4W|h0!$&`(0rH31K>cD_0Lt#pEkTVLf(z~$ob%uu6<9z zx3Ak>=gO_tBW}h(seQ+KQ|cNM+p5+ZdABpL}@0H1!5C!w7VX4?_FT%ekn`o}Xfq`|+>K^A9T4bRdT- z^SutlI1J5en&3>IWHqo0;N=&Ls(1adR>BT;7zG?c3}Tj>;pIO8@;c*Nz)rPdc5NsT zw(K*dqh6R+uUN{1*?3mt@gmvGiQ%I2Vx@|iB(c-aP~H|+vV&^uq9Sk?!puo4*i5P7 zmw1%0qQH8m6_vvX2Q_4}R5sA(g@zen)+c+gPs^@zat4{{J#X5q6QBwFWl9_29Z@^h6 z;Hizjl3>qyb^_8XcA$0N09pNfN%;3ntAAIjI4S^A782Pj26(!K6$UfYhn5!<_qHzp z#`XVVc9*NHKljAy`TU!m^$>d&?}Uqxbpe1>f4|H5_KUKdqrUs&2!Tziq9lZ{Z^psG zu}^EtcwYg#nE(tA(9-8*Jia0IQnvH59_`d@dt{rT%bO0DY`vRMv+=UXL&(om^Hs%= zj<>R?5Fl~Qp2|wHHq!^!kTdTg-lT1rB32mbc^9B|^;52sLtKW_VkT^V#wwK|#nrVr zSOOb>$_)-yl`yhLMP|ScAMrBSo^>uzdpJ-ZE!8vihcW8NUeQ`H#=jE3*t9y6OuWcq zT9sYcn*gSN9UWdD#Y-JYzM5^pzWjG$tAH&^-o@AeBf$Os=2#Cvwhr*i&cAK#eVPsM z2W2PXd%XXL*pO1nl(c#8HN9ooe}I3KBM=oLv)IqM(@RRRcdqe-50t)jrs7`V{Ip zuwiTZ{Gc3My`S#QzTQ&*z2JNmu>I$-n*O7g>Z;m$_S6>O1;fDuFaEop>a;eMn&dh4 zdt;vyT23I(1qciX=K(yIGsqd1XNih@6QHn0or{qUH-yY?=e7~Fp`Oq#jw~aLR^sz? z{*@U27pTC_dMRUS#p%#Ur|9gr1HO0X;_q5^UI+56kv-kbYRh#rC$%47SGWKGN*LZ>^^DYBdE>olMa!t+;PgC2H5lQ)%EGkXLVaCY z5YHk`otebKVhK*0VWAc|?OJ=Sz0vCfBw;1q@LMd@(Y6}5QYz|M4>IwC_qM!_TJ#`1 zhO&M=c(F!dcDgdTw5-?x45ow|cSrXYQKJ_@2Y~O|LELpCltGQ~uTN%v0Z4Z=V|6-+ z)rr)(hH?{cz~|+e>-@uf2~wX=^uqx#?YL9T&32KY@^n<+*Y>EQ#P95qo8H>LSCv0g z2EezQZh$fK=xLzf(Mht_?-4B$@MLCD1nWrjld#LI_6r{uk$J;e=_R8&Kx~Tai>s`_ zrAU%~&oeeM_YCYmS9%qdQ<*snQ_MdOJ?;#RicblVEmiCHJhT`!-zJf+zP|BSLG)P7 z-ouE430nKQjiO41Z9kN7R4`&~P z7eQH(o7KH`;BjCGYGq||{@Z5VIy1pt?KQB}-RTX0H`y-GpQTu7>w(QWasa87)ibe8 z5e{Il9rr%yfag*S^$x$!eon0)5X0$?fE;4BxqMH#+~$r^nLD$`dvbGUYjT9)8Sq6{ z=Kf(=_%7Jlhn?(nNZ`DAI}~xQS-TUZbL2~K2i^U90~RRX%a&gv^X7jaZ@a%L3H!%fMM$$;crOFj=}hungwy=Dg9u#qhZ&x~)$`xMvd3@#BUo0>u>pYy zh;KL_^L=?Vh&T;jyd$`{h$zPif-+%5mJawJ2HPSl;(2>NyjtxXVSNYDL=SP+0HROX zftNe8HC5?8cYatYu>VG=(b*30%gpUV&rmzt$is>fGYp~d_;Q~g`5C{UP{OO4Q#vPu(U&m17UmU0^O{x(tm#0 z%-IkS<~ETe+j~)CCODTKfIYXlrDnRCUY3>@5NQn%G2k#iCK?~JrTnMV+C@L2@$sBY zKkiW#TQ>Xafo!@Rudneqod>`4*>d@}*jg{)3}(D}>Op&!lEL6{;4_`HYR1MgcNfVx z;YU-zVd3!i!{WPN#V|ksJ5XaHjJ%eEJpgsC)*q7mu>NF4@SH9<#oqu+ z<&G2G8}=#W8VI48jNqUM9VvWiCf}^mzhwagHpNf*;TUS67su|vIU)qvX0(OSFqL1M zdPG4&S#q&BH|?{?a^diG1`OsUzF2SA9dno46S&yNzu)X|Gdo+?cW)qgH~3{iv5CGw zkxYc_4$f=|CLK(f9nZ{w;b$8RC%&&C|C5My9!)#%>F66X4}^xDxvbb8odsR_?W+1E z-13(UVyAlyMfI&zZKr#hNU#XV$Gx_?wXt4y3lrJ$;c=ir#@bQko)aJt9$#IcgBQsW zp3Ie3e0aU5(r<&n^aVzphR9l#GpwiT)Ji#LTd8!sX8lJ%E_x|Xz-j#Yj=i7Ms?NLZ zyTAmd~&cpccq+0COZEfWki=Qsk) z>o{|AQnRy5;73^ndrKO=Et?ODd~f{ntQh*&S&Q$}tJobY$Yq1G)VC1P*~aFE+P?*W zc6NWwgPvZfo|JL%Z~30D`nqj|%OMX?(zS9YEf@AjD@M?*S>IG~X#}-0WIt=h3L*QG z(A97%uz5adMo6CFv>I6MKi|BVsXu8r+o^3}RO0UfAsYM7`WngzYnkWchsVSE4JRM~ z*nMRY&Q#(^2p<05om(g*B2X=_ZipuhsJ>C2NZ3eH*hu_=Q znB|3EDM$~qs{Q?fvV3E2w$SwCUrJpg;?^J2cA*5&))B4)NDVhi%w!dqzz=wocTa3* z`YvW}oBAzYjQgxg!%=R?(^kXEKzpDulYd=z|HMT9&Ij|t0pq&t_d8JqtNINS z%ckal3F<$hd5i%!pq-y?$tVs0>)~doKa{ z#d#%mRI5~-(9hIyagbG?X4*k7V9-O&z9{T}&F=H9|31jUc*O!bQ#PXvrW&0yLLJkt zdS9h{d|6Vvc=qLL>fji&NFd-YQ$wH>s9ijjsC*6P;At_(E2kXntIh6*nJym@h8JLO zD08lU{K|3qBaOnRujd$AZ;55yxEg)gGC1SjX0~PX0w$R(*!xS(r_HN`a86dXj5a|x zd|*cgqt1Idk{MB1S~m&HNlkHC6_vP8??Akl_(K;N<0Ve>%Mt$99}ufH{^LVqf48WPI8-*wE|nnCh5{5!|GdonR4Q&f;&FdF1C|9#0lUNzU@8n|M<)Q z^8f$kL!*0?JimEpN#x$wZ6_q*mgNTk+vh(JLPN%H<6 zpLABEz7Mfj?=$7>>+HenMAn>;sikD4-Ag)>H}y=r;|&8oA|UT6Ylie5!3w#eb=oYH zLDjH@1>omcHi(1(IuVi!-t>ZRcGr~#Ernmdzi2faxAeL2LDEOz?yD~E;=UWal$0TT ziMr(YP$)kcWCpo>*^Twqu?3&c3f6|gObl;PO!3!n-G>tVP@-HLO=iWZ1!ra_$C{uT z$`IKVT0Q!)3CgRedo2=^or7l%6rE3-PjvEQVl$Z3{ZdDw`LsR2`B#I1Dk1V)TF#$e z515?T>erLw3EK=5P5o&%@Ma9b{Z|dql1&wGj<&jLm!b7vJc|n&n(JHjA7>|a-%7b} z!}B~B9Gc(b>;{{I?AGJ%**$^57d%yM^=;QTHy_%f-13Wyi?6q(jm&0rO0H86b;TB} zS4V;6`1{hO#rx7_rL|sXGLlN%b4{1aL@6tvvRZ=oygn1*(^-78VhbKNEDHNk`Epeh zAn{?@dkaVV6IgFd=Vx-CmEPoZ?AYL7#@z_0rpao}Yl$>T7K1dl`+XcXe0+R%O{boA z?fYvn8@VD`Zxm|=hH20H3tU$F^JuxWfeWejNtN|$U%z>y6%I9gDzjj(vA5c%HEgTh zLki~7&gf0r^S^ew7u(<~t`^0r#So13as3h37_jk+UE;?Li8Lx!RMcO=)%Y}FuF@^_ z`N4^aWK_G;CO&jpm)qSuSx#;h>9ZPzX>=}q@!G1r=V+p?svmvMyHkEImaAjcN+Ctc z^&#@DtSkc>vY`!XIJu9=(NM=b&p8XgT+{nK(vB03ULgHQR-+E9I?yhCXQZexwEJ|G z)8K@y#nz87?=^gAY+-F}t#8d6+Pk@J;&V?4_180X9XF~6VyW1rSdaF)YG%!2y8?JJ zuReH1O>lBT1a4I0udVhwnGe!tUXT6HyYj#6ivRopsd;&qfu~(MR<4nl-t_eJ2YAY3 zIQHnYd+KW#fKo+W1jA zZ@;ZQF4579De@W5m+rrQaQ;ix`u#}8E(MgG5b(gx=+?Pmdj9Kcd`8`w8x>iIy>eVJ!jo$s5O*lD+99dB+;S9_1Y zqal|YovkIOUh82SR9I|m5^-6H_~F&IJ0e!bx7h-ICWDV6{(wx%l=KmML%_$v7KqKT z!)fDjnP(qNW_BX5wcl4N4{!6>nrg~Sr$yZgUpP$|%-2axNSG-X5nI$juAjP0X2Iv@ z_3a2zCc2MWISXQFgSh6WN5ybo_WBK4Jx!2s$*m~<`yeXzYZpzgZWi~)B4q!Xo)o+O8LHT>{yDSbY#a24K0~zSb`nRxWBv& zJ5Q76|0`_chrl+DP1-%aKza#oIBnarQ!O24k-tKav$|9aXGc#4-~+fLsz(VC1b0v5 zTc-=f1@2m#Svg6^o2RP9Ei(vfAGL&CHUm8l59wJ)u~{8&$-+oWR{Lw@M{|m4z*-pBqQyM+eckA1uKtwGL6d(7DkLMtA zae}+ni#a+Ftqx0Cw`Z;S+snG8O;?~|2-;k6vCK?_HceuQaVX_ste!p0QeN>?uRupl zp|e1VUa>cna?O6nB+_fL*4=Nkeh(%6ozRn5l3PCL6m$}nEL^}S#FyrYX5vyo74MntH*aItZ$F+8{gU!d|oUC@};u)N8DmI4Od<1Jzt3iaxw4G zBG}IQjbr#;Oa5nVO!YuI%H2#|k88N=Rv45xBmwV~zvpm*%|Q&eg$FWBcM34-ojSTW z90m&|2tFxt=9khMzyajQi}4can!2* zByBX*)0JZGhl9svp@eW0WO0!_i9U!m&CkpXTH}a&k}_h3*|&iKal~wNrPGx!pDhi2 zJlvj3?Dy;XR%uZj-+!ed)zMwo?p;=}>mhpot4Dlgn(&wkpw$JwWPmN`( z%|Q`6ab0Y7aG2%bnS1`;qiNgB2n>XfevpAUc7S_*n zUZdq;ugL;7%;c+j34dN)fPbWyx9q|+aBuCgK?zeV`Kr@Z1JLk)qiNmSTdfH6a`kYselhzu88bzSwJAJsJwo-dw_mR>mO<4D@;Wu!KZqg2Z)hiE zlH^9vgH=&V`}*$-Tb%HaM6n_ck0QbxqYdO|QClJ(r;sX@X=D~j*-MnEUu3JASuQ?L zRtC3RdtqaouEU>42^>mAr(yh~t$FkcLaOll!Mm)1>3ba|=pF=`Q&0OlpU-u$(L`1Y zt8|y;WZKf_>V1}iyt+s4s^8H(4bAR1wzq!xg>{f8wj)uU>q)y(yCE`pkDeAh-kd0t z@A{Yy%;e=yLha*FZT_)|K_j?g1tZu&?Lz*z3bS;{%o)A`XUsEee}cs3BB+nAXNo$j zs-K_3i=;}I5_GS>>S<4J@` zn>jN*LjIEOWa!OIOyFzaV$W9ot4#82U}1q=>qI*5{Z>3rqDugADr)VelSJ6lku&)= zVTv3j;-tq98m}BQ)$lH%80qLgvH5nW1dyuGm^sW1j_hP(Q^5jlwE5y6usxpIDI*!| zlcmU?8ggO-erE@3`#|Mi>bvOVs4*H)xD72r@M07d#KRUaQB#SzQ_$LqL*@G@+{SRh z(5l(C`YI~DB=t$7kYCg3kK6lqm1DXIU^tyu!NzXZ-Ja}N5X*sQ^iSLV*&p^tvsoj- zaRDuXETabuM5I&&SDGw-?Q#p*A$YE*D^gJ+T72xcwaRV#BYFbb;`b*Qq!%Gl#tjS- zt3kTTu16;BE2mZB-02fYAAMM_!~<*8Gm1T1{@uPjd7LC81F7PwSIzKhrjO)&3JeCz z1&z+8-u=0!9*a&z?h`7-sH<$5T}b941E8AIwRE;=QU|Wnwq{hN$14yD_+mD@3`}CX zT!6)d(qNTv)O1i-5rmG%N@LDyZ@E5t9eyh&VgDD|>3y;`0Uc!ywySIqFW#;2TM3jK zJBT?l-6dC?;v`#xxVGA*iC#P3_b&eI zRV0|qXC+L)lnKm!+XQ{zjXqB90c+HN?yVFnyn225SjEd=b|Q0~=KH%L zb~C1eHVC%MVCm5?0q==<+KaFf&(ihtHa$3u10FAPJao*Rpy~kQ$8ZbW_$g8ztnY0U z;mUUxXCuHaDB%YOdNcJ)n%)s>Id8ziPgPGXIb!;5Tv$3?(zHqJjQX$L@!ty7{1sL6 znHX-e(3!4hfc$`z*J0H6Sij_XnD#fljZUz`ES(BtPa{YpL%@8k1CdA+L8){u1@*sKkVpI*MCFW9^&!Pvwq~?fjZKx|9+2+k@4M^+$57 zr5a`*wgy8N79y!v6q&?|{ICl@Vdy1|P*4Qk#AT;@Ud1nXpwCwhe-lAMXB99P>GYNk zjQz0@=rQYpR(5F^9~B$vzdD12?c;INHu-~G8&_%DR}~qg)b|e$^DD)n8ml>+9p)l; zq!LO88}97R9}k?9nB{FryS=PSofwF>I{C4t>yLF6cG6=f<%P9;8n*&?T zJQ!28XksO&P)ydAgH73~&X?kvDD4zsYh*Wf&m4WD2^OP8$!kdN{rS^-PbLq$xB}g- zXB)g;4zqCzU0aB89vnU=0j1_Wcv%O}RLP>lU3$08Z8YaCNB$L)0g0B9x|;_YD+w=_ zb@EY4G;WC4kY@ZAic+R~JCDbd;)_dMYp>2!&PEX&XyBnLF)Tsifa{-Knx2u`ZRT#P zD@DWL@|~2KR@W(+Tr;@Ree;Dqzm-R})+328wKFrcTYVnly7DyZXw|Eu*E294Lw}jW z>5jC^-|Ehvv@XKp!#c{dDs46hgQ2SqKf#+FBZYcT^v9|dD>@HxSC81P}02*Q_o8gtnz7CUl=sxjzdd zrk5%`6`{KEp%f_7$24^k8}QEq%J!;VgSIFn9Cy3F#O~c(Z-&8mC%ef?Se7Jw*Sf#K z8XIzl<(JxnY?3ZHmu0TxCH!rwU}uFZO)YYuj3>VXtKr7Ebke7r1Xwjm(YxRO_ zVgZr%f(Jr+Gi8w^dG{&&TiG+;i1BQ_$xs27uBF7ZAQnzYr;+D9eN{3axL~sqLNv$v z&PAftuYfxYDXkL@g;h3mET$3xUns1a^Zrb3PzK6xQLwjvBI!Y#b7vSUU(#G=Gbr8) z=f`w9t!`CzC`BSiCVs_>K|L$K+q+DCtIVz4uH!sC$O~r>$RC@7dv|Kh9L-hU)$LS- zUaL_Ykj!RUCQjgfKR?(HoMuBS?s6e-IZ0}H;@qfJ13E@9KZtyA%P83VeA5%-%&)>% zZ~`iz1U{o+TM^pMr_mk#SP}Zh7uMseGtQOe+BLOj_Uv0bSz* zVl&8YwBB0(B?(Cn{8>lvrMu@d%on`J9cnKFHCTzrdf%}l!q#tE$jiP5dj!Rknn~TFT&a{%BR638+g#`ja=^bCN%X1_ z$aO~_4K6pTD|6l4?w~0+$_{^Au2`g@`*;_tMEz2ZF8d5p!%6upjdL!CX{ToI5H`hE zd1Xb0o+>Qs`TX9CH(Qzi4DJ5FH2Pm>0y+XRsE)0)a97_`uY9-2WhY|$btlfPJ6N|S48i8|nuJa| zKN%aG=0Q_!iQvbzA?#+JBjZ3qZPu+-HG<1}sZF997{5~S zRzROe5+{^l8k;NW_&x3oi8K8x`RaciZ*i+JQ1N_Zt_~aY@KPt6L9^8XDeu@JrPL8` zJMiaRVU*_svex${52c2ZIt>Fm6p+P@72!vncXUCMybZM%G}qm4AA=(%V%|b zZSbitM3NhvSh{%W>)U$Sy6jP&3FS+7Y`!RW#`PA@)DCCV6YelS7?mn5LgA#Pb7(A+ zEHemC9cj&iehAlm+zj2m-S>BZmN=cT2!_BVe5BMZq8vIRSrRkgr-P^dg|$E%hpyus z^e+>wDV8}mfTe`QK($WLJp#i`B~+9Hg_dQT8F``FvUCiav$gIcYz9J9x)0i1rCCWI zX8O+7-BghbY|+z^VeUyV_Lt{SBW-CbzCLa1vWn6;DmF~UHNfxGc%K#@uM)!(d8d( z+~jI04E}4U>qjqSE;gbpW16hjF#{$+_UGH);M@|OO#WZ5fnDfNdIOS4HzWFF3t8Bv<^+Y$x^FU{xa;H~Vv3Ki z@f&%$8{x8SdkXZ zX&cv&G-^eoDS6A5F9VOK7092UhHyArn07Dl2&~xnViY2Fd&sVXO{gqg)aCMBeQ-C* zBLsYwqh>zcUT&g`c8Lr9-d?SJKVLs)KR!wOQCL{GF@s*sc!En?Fjq2qk-GZSt`9({ z0qJN>{gY1DOE+klT-ua^t0JQD72@L+75F^A6^ywWG9nMU@^OLIWFm2INLwr`<)EX; zKWJ3DPQJKCDC+ssPcK|8uK6eZ@%c=1lZ{AaKEEKPmh)U$J9R&rJN44bdu+Tx(s`pN zF)zq-&(%!I_f+}Baf&N`sRfuraW}t;^u3FNFXUi*R<^S~2coXBh+7+5!8`t|{m(XYTxIIpY5#eKdb z*16NovJB$h7r-Ee-gN&kI5>1al^B2YhG=I{jr}3e8%G$Q4CRlR_O}U;&{+zKOL-3X zyvO@25Dvs=$?NvhDs{d0Hw-}uLAX!f?reqKN;lCh5@w#HnbFVJA_>O8zsr)VQC&l{ zSRov)u}(VcC+qtW+Mh}ECPDbVdC#B2&t<^g8|i$5dDhsscbDq#OQrCB%F!4|l+FPR z;3S^D^}e5p!adRlB{AuJM#0zme6W}n>X)bY&W~p{p!wm6#Yhx&aRKMRNQ5qbFViI? z0>X^fo`-B`rDmHKA*k(12Af`W$K8`WXP`TcXoMo)zIo$ha;3qq=fQpRt~&LF-ih*R zVXeZJG<4igF{Byy9Vsf&9)^iYZ+$LEzmw*B?S}=~5>Q*Zl62Xr&?;y2k%@82v_+xw zs@to78ZZ3`AD!N$`CPvmc{D^}_GKSla&YGKtciu(z;|>f(dT4@T)r;JviQ1bxu_T> zj?;zeaD#KWM|kb>SJPPeEOM#nQ*$m8k4TW`W8udulbAqJDH>6#Zc^kaCs*Z@#47B9 zM&k7$LtI-TFVDdSM+1#xnsCWlMEw~NKPBVURhrzJ5E@SiQPu7D-v&26(CoT6h?_^`@Xmk)C z)*E+Q7ZJHvVPsbuc2t5>OB&e6pJl(;-pKau+g}@28cCdmd%M6oG02Bo38_$R_c+Y?P=zlPPB)6>m5+TT{o3u4GfI_Gq(Sm0I+GizL`-ktDe4?T#OQA;i(+X3g}Y zOb90fXn-U4dhqeyYThrNgt52fpKp5bg&FgkjdBjH*bM~)HFJ_vA*XRObfrbr?$4s+ zJ`y6(AqAOm8ST5>3fat78?|7OGh=J`B4n{n)hkoh@nTZ>I*qukFkAr}ig8p5xQZ*8 zfEsUz&mm807AkL_%CWN<;CXS9S>C-_m_s4M*H9>;Sd?ezN1@YOiLE1VWGz>^gp&}% zhR@l-ShDOS<4@r~ajE}2P?e7-8}RTy$~0m?KF*thecM5NB{!ujeJsB_Eb;mJy#KzU z!0feUZEoyDNq@*A`!KoB)HH%>?c7G216Gj{;!4a`DaVm+AFaL;GyJ0Dh6r?Gd79;r zxV8X@^ZM0N3raJoA%Wx0`5X{HTj6_cG<{ob-ZD2`F|)!SW+F@k>?mL8W{4{-F`xpQuaxCwc)4jz)J^$}8np z!)!__Hkm?Og0A~xoEyi|be*tSlAJ=H_p>BD<-ZRao-^K%<7uac-R_Y431|QlfrZJ@ zGfr2kEcHx(dN3>us!=p4!1&)*cdUHL=<$BgLp|RFD&B?TWqn`0!Z~{%BF_yzajr0f z@%`Bw={&PhRP@gV_Ax)oAnxrUyP1yX?K^YbY_uQt&PHev`On1`g3&(#dRh&^UfXT0 z4P$?iDveM^rLPW68GYC`FS|vqMb96h80#qIaH%Kd8BQd(;lay2Y>=QhpK($+`4t{> zUEHN0P-_9pWlrU^1aoY3VY^aeigd9by<*rE?Y5T$)tU{|)bK|mXdkX07=qR!MAn~{ znf??ZH=ytE{7^3ItvVKv_o2lqN9y8KT_B8R*88HR(ZU?p-xm&jcr@*!59y1c$1O$4 z=;Db{(m!|93919Sx#X;yUKr^`+&yKB7MS;(_y)l;sODShy9Cn}F29?=RBfmMB{bK4* zdVqf^*mG2ukOnafd`9=rE!!r2v9IDDm(4Apegac@ni{#tK-mjAW9SA5LLTK- zz*`dea#pZ|3pbI@(X5bGLm^Yv`w$nDijZmu{yU%Aa!?fPPO!Lt?gRgcQhBwjf*r~4 zMD7L{O9}S5j7G!CR;_VYuad2C*qUZ|NOq{=mPvf%EhDcz$uP86&c}}n7CctQF-gvM zarwsEKH8{mNo2!yzoT8#2)?dpR`b2BI8Jy~9uaekaXEYXU3`17|DF5W_>?X_U_l3& znW{pOsD@Ia9_v4yZ1aS7^1hE5{T84vuut;t$r5r3&|M^?ys7sOYO@-wdey=5{KgOD zz8NEVSDkU_w*6XhUo#Deuq{fRdfFX||04UubITn{HN_Ozh>)uhboc&*S>6+H%MCR1 zaeW4S+6i?GExQy!kT&ed{)%xY(tIo}O1g zs&Spsdq#i*PM*cmz`p2yVliH`!_0HIsP_AQm*Uk#0fS>)9G&w z>C$x-4|7qYbc_E)+RsufImb+fMXRPmKo1}Pe*Xy(_ zvha-}TwHsa1)z>Is90r0Zq9gtVj~_LF@<15=$2lKOrIUif^=_=`0t4O;+kZc+#m2) zCwe+|QnGCrcYe$nWwbecIYtS+v)td6gOlvyI2rn?+c-28UINv5^X84+?6hR{2CA1y zm=NA}a;920%TvEL+~1(CmO|I#L%sjNf+4ZrS-U|!{ zpK4H7t5-iJk>{e{r!(^!cbW&uk}-i!Xq;Ej!uR!$d0fm<98A8?-s_!wM9_>aith!o zJ}KVi$UtkLnCHT%8}4OE{Dr=}^ytLqFB@WFknBgA=m@&kWUm~sp;RFFQZ$^~2^e8G zzog6*J&eHcP`NC1)B0L*kjXg2GjQ4;wp(rtkt;OU{3{?3Aqo%DU-q?CEyK&Hk#=k>>K9!X7BBz+q05v>qB#K5CfFdA^@ znQ7y9$Z8M6le!1l@B;1Rk75oUH{~d^UZKBLigVR?!i`cy3T0*Ma9I&---_peZWJcT zI4OY3^xegkhIUAnN%~H833Wz)M}<{}b`W&i+W|FnZ>+xKVG1L}(c*zkift8(Vl;HO+V z84u|gM2FHV1vE6@){2(bdh_Rs&w17A=6yW)o(Ig|;!3)t8)fn30b>YD$>R< zBZn5A_^WAA_(knorI`kOZ>ZZ0bA|Jz9xKEMa9s@aWDCl}V}8%-y6s`n3%l7m$?DH} zhfUWaL#pld=_qH&xfat?ht~4~-u@`g=6Pzpzka&lww@HSDlcCH-dg zHRTXWq_;L(3g|CoLjptve$3;%;zV;`21*|bqg4+6`fjxpnX)vVMY52I@5GU0>Ov-t z5NuvyB~?vdXivfdS^dJAxaA^fYVae+P5Qk_E0Ub>weJa3=Ny|H_^=#&L}#0AT)K64 zc?_a~Ln8pBr^wGG0o1*DXZD^G4fDXX>}%T0?+Og^z}CC{WRJ(mJCjD2(Hd$e-^aRm zi$uVXG`rohTA12m?esKM9{9%P4np0P*4EO@ZoZ*uT&*sS=bPzL2w|xMniDvXrzvB^p7vY~l;BCR z((d|JYYHg&a{(lQJcxkXa}D;-SMcfS=`C(2cH!CKKq-^3ZLaXWXh95j=@k@rM-U?V zfr)0a6$$Ns zX1+8XHr*!nLOw z#89|h25rvLJqC}~Hu0ZfJSG#rmy{aS8Y`Wd%yCmj^?sYcnMJsn`tIbHg@QDZ(hW`0 zK;0{iR7?sm#RwWNRyxC*YKax{F(#$!q%56-ZL0G6R(124Ua+QJR5mQT}vzD zx8Tv{L}Iu}%3a6E-WS5QxrDLeE}gHRjgEa_{cGEAM}I9bvx$G!0~A}O$`Lc(_sl1T zKM8)nBhi~IDt*w-kiQvePxNvw!O+NP7-0JnW*%2H)i=rt(tR_mmXRv$?YUn;oDir~ zsL#*hc##oFaNnp^YEJ@WcwUZYHIuO@i4Jk!3%B*P>Kck}gBe>o&uHPy#Tmlkvi2RN zyE5cJ4d`h(w%}hWK^}U+%olK*<4@E&a)02OKsgvLZT?q1wL1j>(u#WX*!zE_K9#4v zEH*H3)70aQDb|v94fA5dCFlKmL#b0$L>O@bMHT^Q;G{z;O%AkqN9amlF11CQQe|-s zr77Nkc@_pjK;DN;ZA$#IYo!P?Brb?jDxxSRhoY;%@?pUb1!_M`ccsS=7j>I*@M*Uw z?uP!ZxeXiq6NMdrLqzoHJ*1<>h-4hZ8o21O`-3PvD*rwD@zV@41*i9s#BmBZPUPnN z)yp3TuX6K47I>V}VWr;%COSbUy*GmKbk3N|%M9!cDHTgL*VgX&!Il7GJdQ!C^}UE% zJ}bA-y?zo|4=MeXXjG&@o~%8Uy3_4ook#EoirDv;0Lk40xyeI8B^#0FH{7k3E5FlL z{(r0Oz_RfthDJkk=dbnhYz0%`YnHgj4$;solZP@Y$D4ZsL;Ar~ej9b$CiOyqnv{zm z39xlCw8z%!nZG%UnypbI#R387En8tv;S}1ooAzVVEU$gm9Q5^>HL|*zgYKJ8u(i<= zQmgw?_a};UPGjiX=M$Slff`A#cJ$FZo9wa_3#p>fV%-x>kX54hio#@ z(qT*TH_oeU*Gxj+3dmrIYtw7p5Z$$ouR@Lc-7>UNdG5z~c`SYy8Jvxgp5B~bBNZFG z^OD=J-q|Ka4(f)fylgt?gptNHem|Uzm-HPYBQJewe&t+tMs}^Qa@NkvYrd9OYWH$o zp)k3X7_}bb@Q4QO%R`nU0bDH>$n1)rZm{`m+_;P3tSG3uZa3_D-<%`3gWX3$D}w65 z#A2< z+W5&0@GpO6c4Rfvs2=XwH~74O-AbofJv%GX$gDpfm!CZH6I{VZvnIm@1>OwY^RWn) zTPJ$@IJ@p${8cuO5#o8xvWKs zR#x`+8R({1N~fh%-CVq(nJC(UTd{bay!Z2aSIf)yud;Z2kAHN69|*k^txd$9TY+8# zG1+%@22}b>Iav>wa|(sY4XCM=g$O`oPF-kdWvNy$fUJ6yLbEjy!dd5R9Yqc2u%hY` zcWD#Yi_x)`8VEW!p)36%ScvprmYh~Ch)dix_=Py7EXQpH8qq)9sQhxe+3}~&wedjS zyoeohwv=437x*F3Y~tyfT?7zpk?zh50Kj_DRoLWAku8+dH($*&BYFXC%^f7C0pD8Z zpw-%*$Er(5n-GQhMPdA70Y^!OUFE|{q7B@}XSiM4LqijRHQqflSq zVG|XT)uOQsoLl=*IWo*}p65yqzO`N8wxkUFuZCW}gacL)eH73sMZxX({35-+tCWPeC%_nM*w}teva`+gcsy{p3MkF z?wdaYgh1ur%UqU)l=pPz>~Gr5u|fLMQc0hd8p3egz1TgyNFLp53IRtOvR?rkoiakHUsnPp|+o+$YmzpWGz`_YKgPfPo2!k#Yfi|x*qCB|jE?t(Wxbozt1 zTgPQESKP>nxD`J!E*Y;L?;j?7BMB5Mdaj(M0k}kT?A^9zX-Rnr%p$LQ3@sG!l(OW` zzwHNlvVu5oJ-YS*Et^#u-@yi-u5V7fq0ONQuzTe1G0rag<4)Dg542N6?#(z6-mDpP zB2-pWvO=J~Uoz zB6FyAA1I)CV|_FcTGgL27amq_-SuV-h3z5f=W(LGwpA(XY#@|P&_8$i-Mh64-D+(} z^(CBq%JiGKCbp9OvC3@i!*{FI?fiyB>snwaYKP0_CZg~#LZ5qj?~RVQZl|@jL>(VZ z_2SRy#~vQd9alk4&xQUtD*jKVoxinr^M=3}B{8a<9J zbW^a0MOa#3wdtp9YD7}2JeUctemL>~tL3_@yTY4UmloHcdQpT!6kEofV56-{@R&K`@|6l?1r<}c)l;9`uiFq@z2y75Z4*E%B_MSPvVlYWF zy$?Ez1e`G{_-&(cEZ}WnjxiJN$daxU)+%v@l-Fu_vhe3Z-ig_JbMrrLn%{!w$#>BU zsFLT6AG7^!h8@3*-JWyAGvMamH>{e~-Ib1;%84Zp;?U#L>4J>M`edzIN-?KSO^Eb= zz(++ziM;8K6R}y38xa!}PwjKkR?cb*o`O{0Uje2dLuW_dv=*~@F2lCr?kD$a)E}D< zPI=$a3eSEQRHguyNBGKfJxO!$%>qb2}5!6VxR^)B|CPhpXB`nshci?ghxKuYZw%Xu>HjUn09n|hI zpg_hoFZU!`D*3=x8FTF^eY1}DR`P%GB-&>3;jqUKWwNEb_C3spnLIN4*_^o_rHIBBLGEm=3ahMmd_LK6!vuPM)Yt$ zQk_dDoq2?FMqzZu&kVVJeBDf5p)%~NQxbC!%ib-+Z}Y*;@3I`LpndDpCP8~UkeJr%m?Ybpl>hwc%FF$NERfg@&> z7Zn6vNDHpoh~`L36P8^q@{SO(@e@)!6<2B>X?${Pb&*SZIjwfxm#{NO>arMcf9ws0 z@LTMDo?YQl%5roetGN?q6w8w_WNQYG@dMewEqyT9m@MsD{v4W>EYMh9C@tDuPa<3W ziyPE6zqpElJ1Peg-cQm%o8P)4g;h&toNgFXgwdgo?n)}1oYtRAZaDGdMgLd3*xZ^d z;+OZDEABk0Y~c4$jsMH0WEH4zoCq?T3xhjXIZEjnpbDtRt2C*F)vDaliA4b{FF;ovw%PMHZI zkTQ`!U9coqhas?M#~bxyK=!!K>xxkjcnpkjnPM(XfMy|dsem=6{G~prq^17k{g*FF z|GNJI@cQT@4gMc-Zygh7psxF(#kEK&GPp~D;xbtALUCs(Qc9u4-QC@FaEcYDxD(K%1&V?W>?|dt|GFxnf!c}dJU{^3pW@>FBq>M z-)`Gn6gLL{AQo2kg0W;P#PB(4?C&D^dFt$6hY1(SAdcj}!NL$VFG*@y9}NAG_FklV zLqIsA8qw$Lj~5KMjpaI(QBnzdYJ!uo=Jt<7*w@I)WzB(oH`%QrC)70Sj{BoSMmGJi zk#gFQz4epWRslxA0V`}$PD91ko0FknnOeY?ETT88P6uQFRHWVO3Ea!(S#{vNv$);z z%RJgSYI=$fax`-859AZzE1}c^In}~VyBF{_m1wade2W!R;2H4A$n$28lLy`!BJZ#3 zp`|of=g+A2mUJC>5zUT<9}6tpUEYaMy)j=Fe{_;J^v5dOY^5E;^lILVp6@)rl)EJs zo_l?qt9hvlRfr#Iw|^SX5i5Aw3z%rvYMp}>`bk3o;kZ&FAx*waDp_e%-jKZeec$TK z*bncl;H_Ud19t$puHc>Z;i_v<%us`A<>olp)6R8;6nX<_+WW@U=9Vtt>N2jl@6@Pb z`!5y%Fk$OEK~{*?U;oGdT_xrZc!31}M_+ti2gKg+!0ljSo7<|}xlQ!OjJxfyStN;* z<9!BRYx7Yuz03PxKIoNR0oGyBYwN|l@`k;N#U3ti;_vd~=rr>bfID2u{C|yNT-k!R4?woT$csMst;`F4qyq z9XcEj873BQOfUuMQu5>NbGb@C2A}>9&NtQ~l#qpxWqa4y7eZHUDSJa!Mlx2;asyqoRJ1udI36rEN!no*62Wz|2{#^JKZ-+o*5 z%-0z1D5g1UZ6P+B-=<`!3L5_Yg13ul%R;bGY0ZwDQT%Eifh^FmYVvl(`M>k&D^8>~we& zizv58UfI})aX2pWJ1n1aJl)3n7AahV$o^<{s2nBj-^J2e{`<=RkHXBS`p>Dx%jcK+b;sv5 zz~!z-CTW|KQ4I&CZVTNRxSzn*+MyDei`D(SuiMxYQ;B-+K)&CwHf>KT(QQP7OWr?} zQ#fkyicqs7Kx?1xUN+VHX(18K+KXA-amX}dciJqP0?g_s8Nz`AqKCg#i@+_q_1 zVPOIri-H$fC?--!IAlJBAf%G#sW>hX7^;q2Nq1dx#(M$2rqg#QLXI{&C8HoA8alwD zNr~ttcW9W#5wkd55Ma?N2DC@f8HJP*&Rrba=so(5tTGnvr(iyQA2tztk-xWu zl=y>qSG41M5uJhoxa>p$u(2uuEe{ee8q_{a1Gz>2B5tx4PA4bjVe)z=m5)mBChMUu zlGHJ8XjhF$asxcJHdCxJlzBaIdsTS3-&!}(zu}Y!%QlccPl>8fb#DHxVfYwcQ7Dp!qs)(@kO+y zU2YE+Dh?5X(;K;j-)92)w4E$!^%9a3e}?&VUQ37h^vy;-tnCRkBjMla8FvPMvu}eA%fLn_*nP-@#eQMn`{=1s&1QrfS$*B4!Ekpw4+@8 zc@K9L3ZOsN`JLK$t}8d1vi7IZ8tGI5F{fd^mIRjKEhR>87FIK;`q@)Ochv{^7_5bM7&RN@C>I;-G>&d4$}8Tt&Y`LY8oK zS;E@+Fg#rI2%~T5i4|9T&)C3e<_83zMj}UvUieKP*(W`8CnDB+o1lUMC@th2TZVntIAnKe%)x8D}HOz4SK%4f{+v*08Zq25} zrqcg;8qd9X3)d7CDA2jVr!I*tThQVx^S$;l%!F4|^WhEYIx7n~IU?OVIcn1C3cX}_ z4Y!0JY35vyc~t*{n)r`Ta~k^OWG=&F>3t+|XZh{GTTERyvGE*FV$&o#FZ7%+B;vz5 zKxc)VL~NiKvA4o>$p;assl2GhrW)#FwNgktk>i~ekG^F z6fEAWARoJ{Q7EPe8^a8W^<%f&uDwv)43VQE6 zg_s+}Bnh}fK?~6zkux|WLKE9WtQt*jb{j@Dfln>Z_pNz^Fj6n^{!5YB1RQF@u*j zv}&AnkQ{G^RW}|ucVNXqd2=cq5pMX{E2o1d>O=(QyT_;Vh;z`&_8*tDzS>ZW?V>Q4 zE8{S!G>qe&AEYqarJ7M56rw(fXQQ%~_em>Y1Jqhnx|c>i=E4{LK@2y+OTmXCyGZtTVl2n*P@)I?Rs%Zr*^e z9#N6JOUsY5uylR8ZUaBW4ZIXJX+~7H=V8r7c^eve=N^HRk0Rm7zKPV7s> zy)&{Y4(GJQ0w;RQAhbh@G$rs#QO_VEjpcY4?s>X&1jxX5i|dHHcwDF(378S(GV6Ih1hA*RB6{vi6vXVKTxWPb zwfoMi@AGJ+^C2+hdL@|&{?nc3zGvZbdEv0G)EpR31nB6{E2+Hy-Gsfabnjgxvx$`@ zHwh{`WVN<>Df)FYv6fPOewkY!Zga+8698NTeI^kbil{{zBnlk`1nXex@@rxCh0smF zXJS{)N+L}WUL<1LI4s?KWGqx0OSn?!1H2K$H){QBo%?s$OILI_0`w2`{K4mJANtT? zXXJ0C-u1)S3sY*Lb%Mfl?IgFuZ~iLkfTv^--eg~<_at(`q>4a$3D)rakI~#9wNttV zuuGl-cNZ57*~xR8#?ofoHN0oPv{;kxC1&Y>;VYe&dYXKLTtsrfL%CUJPg&7I<@hzq zX#47^*G=%#?0XKXm}G1^1vVB$!yNgr<6PQ-XWom+eM}c{(U$UD#t7BqAR7ZsDlx>o;?Z2(L8R8=SYIn+i53MP5kAr4W@34 zD5<6P16PG}sBgULr;#7WP%O6UzpvCFYt(U_@r<>l_mZ1+Ko8-Z7xjgyzSo(G6V4SE zm9G`xfd-nO?2YCS|8W5@bO`R9EHaxcwp^n{h5UyPxhw)o|B=|KE^$A$>reO@@iGs3 zDX8g`xAlC^!XFI^TTGll=a!S}qm8~f=n6cegHFTq$in`_V8`QhtSPFzL*1mt~|F_kBLDPFrj?oxeB^(GSU zv@{tVlV80U3t&!@b&^qxY1lcF$KDE>vP5BLFgRlU5Qf%E3c88H@2Ck4>oc@I*JRH( zBmxt7;+j(&4C8SpWsXa_50=R826mhzp`o%|&^@uL!_Sn=9Ve3(<1}D+^`z8g?9+8e zOL11SpC_a#=X|}0?*ske_>1%7SH9R~NaLs>|!K1nmQ0C;e5gYq-+HE~6)?D%AJBITA z2o<;BLPdR)2m$K7*=G`?Le#Q12dUPOv&nh2Z|6g6-sY^F-8o_paOv&7KHNbkA`45F zW05XN;v1jR@9|t0e}M|>gGhTwnDF(@Gr)~R88Me zAhC2{N)dsZ2F=Tbe3WwLkY0%N$;Lu1jFuWuLHqq-xGuf#g9iMgA)`f1Idc|1gO6{C zs+FT^E|5rAxAnKcV_2YGZ;LCVhaY7pC?|t|%e)e(=x4X~uNCDpNj0Iaw{;Vu*>#@H z7f31lwd?SKvTWnz*AKY#t&AXz+svcId+2j%30(Uuw4B}{?DX{r|Hkrf)%bs(JM02! zB;dg>i|zBV<8QF7bOYbnoxu~|Y96%2zWO`Z8&*gcAQwtZ;J8CE_&PPlrc|SAzDY36 zF?Yh)*Qq|nDhFO)@f2d4h1&*IxZ}CyNGWB*)VNE@yQ&JW>Z+XhvIXAh!)f7F@^dz`ZC)91w=BsQyw}a){be9{lNWLox2c0+-HV1s4~RZjdVi|K7t;Ltj>8b45*#v@;Do$6u+}O@N&+He$+~p@Y+il5!X#0(CwG| z2Fc)M6~C`YE_oH~OFT5C74Ynt2L;kIZfhjOmjy9tA84%*dxlsfPlg*#UeLh!`pqhz zzYp4wL?ZO;lP+$1L5#ONjpukWspAzPLsT^d+7{MyR8u&V=7s~7sPW9BAX6E-!loGy zG=XSCvdzOW=Unjf2%+LX0BmjAo!mt?ICVdvsK|fCQ~8sl`Y){y{PgYasRP~@xaCj6 zuaZ^Tn0>mt2383!AO5qv@y`y$8KuAMyes5m(jgN%#jnrl*^NB%m->_!f-5~ghY8DaB&XGa`R@7*n zE5gk`wj{O5pc5k1M_uV!jo(qdmPvp^R`CKmiGCX3D6v3sdSQ>$xpe{~P>m`^-jDiS zf#Z3yjXTe@7IuQ9%EduXXo(cw-84q&ne_Q?ET3jh7N=?HCsJ*nXhwA2yEZwqo`JNC`mEt4Y zG*s;WV^nd@Z@KZ%%N}JjR{R+#I$_6elcl=XFTKwvwBfxTkq*2w`Rl6iuN`F+F;cT1 z1OJzQd>XPG{!sOL^8OoDPdpfa?`1raipFzTVBjLl1*c}ISUIah0(}-K&^~j3HOHZ4{WHoptK6k8S2wc|<%75{4>W$nv-!tnj zp>D42M;_to`T|XOGx9YGdAH2B210JotpB$}0m-9#rOlBH_TD?h{xwo%Q%1CPeV&!e zknghu~77grrR}5nfp)=5WG36+Xo~6FE}<0c!Ktk zZyD_y2$3$7BI&~ifP~EhL08n~XPZ_*p;`9`kls)x5y%DEObdtOE~~+n%&?C5W~zO| z2Td=SNeKi}@*(d^>;B_T=qJX*YG%hW1*mWSYa*6(SxN|g_bxJ(|8S6Ly8B>ZXv|4` zWNh};PH29Ntnb2Cd6aZaVIqLR-7ItG?n_{WP#l~1<5{<)SG-rXb`1vq^i){36W^AG z;}(nMSiEFZ!e-`g_Bb29>BHbVC3u?im)b>ThcARdHp=c8x5-nw4f$p4l7B04h;(+8 z_%F&kW8q;fg%xh^g4*>D_5Kming3ZpW4d(P_lF4NK~$-Kpt^GLhN#4$k4oY^Co&gr-}*z&sQWBcyd1izz)^!_ zLeza`xUmg3g>>TL)N{QI9a||a3(^*x5x_K`g7&$HQqf(sX1nq3jE6XTUNX@L7I{K3 zhG?@nMNP@!ptSN_>2OrIrJMi4-xveM(G9}9%}Y9zLLlBUEawq57|)$j2pLYS5e4pY zt}pZ?0uCdp7AlBIy$@N8t84L`HV9H_iFXNR5aF1vxV-;6OxOL^RL@8itXQ47pLJa^ zv7YyTRLZ{6b$PCJEVy^TNlVVg#EDB#vzx%qcfqX$P-aYB&X6ha6}h@+Za)6rNrUAW zmDk?MWhkE7MxOW6nQj4Ew;Z?uQkxtV52wI5QO}Jo9#_RfAcQPFR(PsjyQNFWaIi*w zH-M*4T@1;-)F>{B06d&0I$*L7J1-Z!D1ZzmCE6%~dIz*!4qgqY)TZ$>34P*x=(l3w zN;LUKjiQx*z&rmkJ%Ls3YIx_IVLCkNJgz3ic8|z?1K9wQFi?*hu|+41XSb0T%R#El z1ED>vo}&=kgS=Nk#3VH`QllUEJ|3!eZ^6Ec1qa;ib;Uv=#?Xh>!LeFsDJwjzNT2l} zrntI4@oe2nF%_WP|9jr_Cntkfu~qML*IT9Joc=m^t}N>Gw$Lc@nFl<+5p6oCY}2qV zQdmm=&xVkH?m1=&;OdNT9h3B={W3|F#HYMfOyYxu%qBtr*8k$^EFs`llIhg}!13*m z_||(TLtK%{8wvt&WA>PqqaQB4!PZx*+^b5_FdP=~meEpzuFy{?lLI-@H7`blI&|4$ z_8@*}nz;6!^uDNUGw+%90+wH-0gtN4vdx#ra7sz zgd<#48&FwaPi3e%T&34>fkcNEWhdIw#cHbK#ac#*r5zzVrTWM_e;_MfG?p^B|Aee8 z;D<^#QwMHrf&*bw7T+KVb=qETw0FJFgbKoh9I_LglEFJsTSJZFDY(a@rnC~1GZZyh zy!(YC2p1T5WY+$2HS&5KLCTF;2oC<72H8#K3wD2;I0`OEp$%Ia2>C+daV)BR^DXD5 z?;};L1}Hjg=o3K>BwwNq5(FHb1kIn%cpzfC3{Lh4(24dD{0p-p^TB}i3t1n$pQt$c zk!EN0*A0+e5A{1}Kq&V?*F^y^f(b{hOC4S%Ywq$R$@c<;)cyyVqzfmcOV`U#(%V{F|!{$Y}+0p=0n|6v>|7x{V!9ge#;y)9doT2fpU=jCUxF0vOpro!Q8I`I1WW88B*TAhT_(&{C((o&x7-9r|2*Xd{GNs%!}q0cn*|pU{ESzLLrTJX!VH_W><i!=w#y2Tq3xP4(aAmHI>ar ziSa16c%-&8G?8jTUMM|{PIbq4ktwZ@GW2M_VXZYw!YzQY;a&X~5rX4f^=GnueLm6{ zoDqbC^?zuFpTRM&0ij^gOQ*+HsI5xg1Sti44JLwK!5t?HmlK9`Z6B;{CRyb6C{C8;v`KoZL(ckgd@!|o;pYAw zJmYN|16g^8F^fpwu$O4N0pDPBI%+XaH5Q!US}g6o8f`BpnP|s3NPNfDi{0nVBaf+z5K(XAcF_$KL-7? z_~`b#Xn@>f^vjL9EaFIrQWT5atm1cDq@K8YgJ;Mrq2b(ejKGEPvy#h{oSlPhnw>zp*2#&QW@ z_Nr=o;%B*baWY#<39&sp$VD|{axNu?QY=OM;i~TH>0xZdYX95nJa?uwUc<-DA6KKX zk1G74K3g*PnW;}b4I)<6Y24l(_oPpkPf3p#>yLoLU#|QD@^YONY@G!YUq3WE9j+d3 zhEi24DCD?b z_{U><7EfojJOD2AebRYS6?TH0eI@*K(=6z5^$`vqo|pkWT^|5R`8wIQE*sf>*OnOT ziwXu}id45QZ|2u$CJf}{zvPfV~a8hEmt#Vc&Lc%?)5VvkzxavK_4*`<+ZxcSwsHEi|v3 z;i5&e{;T41PEbb{r(s(fr*Tu-xT|Z)nz6B#w@Ai|+us4GmoqyM!|$q}RR3VBl~OrN zA_?}d(s>VihyLKKEhniXNjT)U_1%9Z6F!aoI&6ORl@rNFl}o=V_uJ*qyq>oc+r@9N zG_2XGetvSgv9T0(ys1ceEB6QmelZ;T@T&7I4x9M})b4{}XY=_wSm9UV#c4=K$J*@k z`HH$aUdr&NFW8||?+*Ree>54x&)9D%6B&1(#!ldz@@yj`GO*)5MaGB z)3%AtNYByWD4Q=Bv{SlkZu#=IPsa+D2`WtamUj;D-mtY@B)v2C*@%JNx{Rb>TERrt zVXNY%r{|u>!?k^f!^q!D*4*vKid}nE;@4(9%Gery3mNxNpM4D&yj9%E1mHyRud@=~ z#dz0`eN^H-t$gU5EE*p8-3{s7Kc2Q_bOdB%>o0%m1aW1zC#iVb-IKo`6(&(t)Hn@WM}B)Se8+aE zzF*{Yc(Oa|SYau1p3&4?qsvigwNi;!XzvP4*0*Gb;}1XVuj936%W0g(PfQoZf>gXM zLw)((e=6KUDLY@oR6tq!#r>B9YiygxZY>TwGfwXHKExlTJYRO6oED$Eie~5+bA>$t z$-y2I6bd>wotd1zghH<1_&ryi#&J+a|EkxMz=Zszs%>vi5OQ9kIMV~{Lra|7KLf+1eH?A`ud47L9 zR`T_|Zmu`&?sFPA8MzbdVv<`T96$p#6#Zga&=>T`SX;|{OnrhJU!|VDRj@rZGsyoZ zw(jvAe(t#h2o_)Cyor^ZGwpi)*aTNT_@el{MB_s$vwSy(Y+Dgm?&C+0J_p-064$ke ziBfBXg_4WS4MG5)qPfRlvLZt@TK-s1fzg#)mw?Z(h_hG<5XAvqNe%+}+*uLbLqaUJ zxCj1uP4I+a_5e7^)k|6i06+ z(=Tu0-*q~mB>MG*h)`cIi3qlJB%JiU>E!mgT1$FdQdxxj5k!!q zY+rZiUesXjbm-m=;*hNMotY-A;stOrp5kf2fq5Jxi>UMn?B`}N33q}U77K{A)?Ywy zl$HOwaQgBB#VuC{jfQ~z?cqUs*i%#Z!-wF z^sVu<7j`8H@ZKD?Wo%iLh@1DHEe>&%tw+ecc!ywtX+wOUwp3 zLF9J}^mi~vpwiPS_~E!1M;34(U7qb6EuWT^gc|ZT; zd7t`p1d8n+)8c>n3B2c;eu7LqS?&5%VLC-e0q-WB>aIE;MtrACv|1mp!S0q?1&ZrW z6Kl>0vT9+-3W%_xKGMUf%AO&R~=+|6BWSj6K zL#a`@Hq~%#h3r*V(jj=5ccPv7@bC^z&zeSz^N>*$Zc=$|>w}o#_W0ppjQa`X^YE6+ zcZ;QSB9dygb?CX^y8i2dyJ8ZgN&*Av@K0%|%?03~l}l>76zb^s+jX{{-%VP>y-7nB z{PR2+kDGGf!N_gnbGBEDXIyjHd!%J|Wx(RQQ;5A!OswNfw zz?Cd(dP(C?W2AX21Jx=yg7)gF-AnpZaBBshwPva;&QbZc5~cd5)$Vp28M|v zIw6=}feu$qy?w;u)rk`IEzX}5iXw=$s0A$&MJ?r0sQ6ESZW1o1i%ck!JB442gpscZ z^ZP6HT8&k*#j_Lp%BiTRII~5ZCCK-X7O_a4lK1teDwUWpP}5}B1qfg@HhrvIdO~bQ ztxid=M0|xEM*`lskBkX1#$7vDm=)P?%Oa!%Il6ob-zXb&FQbe=dhj}%BtX4l!$t@< z$ysXnq&SxG6F(KV)4UR>h-Y5*5Yp%k#Y6hohE?-Z(Tci6=cAs*X6y$9VM6-d^v(pS z?NxLe=b@BeB0Gcev?wklOD~_$&J4@d3NmKPHPAZtYJR22Q235u2|mK+P3&_j(L8QX z0-Of~zok?f;+z>i9;={?59O>1OI8YNn2*EWxPKF|wAPW_<}L46ygw69Sj0DZ*|7I= z9mgtFIP%W>MkXMr^QI2v*X`+J_s{$k!EdMZDAjK9!edc)>Plx9l%`-<=mMO~>)^;& zPIGvBov4iPdDiIF=bc;IhTdFkyPStaAien%3D@<08`5NWovo5R?r&zoFFKDnOU|0K z{a#wkGlrydNmnACtkr5cmnG&E-}5f#A|GbnpmR@iO9ZP2qT??uD^dh5vw6~J2e<+f z&$vM(>XV(B+0+AyshV*|59NyTy056t%@wCRG#6j{9J`Cuu%>D!WawyV+)&Gk6cV8eD6JfpDfkD&_Pd07oy_W+g z``|D3-D#AEk) zeS0R-tt@*RoWCJqHs5dp(NaE?pJ)rbHKu&Q)L@n!0@O;~uXx9o<3FRFlw!G;5`PuN z9%>nRrdJ!Q79K7kPX~TuKViSm9q{g#Og!FWcuMMC--h~5r%l~70p;`E zMPro8&F1|dAJeO;`&T|EbKvPxRg0RqZ-7qz0Dg|47YLoYQ(5t~k#tc4_y1%aaZJ9}G^{lF&g81TNpl3~};ogf%&Zqo6dHbJilADC|8X_I zz`NKlW}SPRDZS!j<#&SPD^&yWu@=!Trs-ybs;uG&Sop4On?_V0dntD=Jb%^_8dqbx z>iPaFSX~!>yNDymDQN8fj9%A8*WD)KbuRw;S*p$>eeN@ygBfI1Ty&Fkz`N#OwLJYv zSIF|<#4d{Gr@m6t%TD7SlSr0ZXzw$hPp}xdk<$cl-@*L5y#@uGAm4-X0hV9z*9DEatPGQvg2(){;lO!<3>P zyC{k*`Vjr{lhbXEx5Z^j9o}^Qx(=*P{*z`^9?V<8Z-?Z4M03asgcSRa`-lo#1bHK6 z-H-xY1K1Fz{`>7HfKSrqZ3?@e#g$p?U=NpJLn%Wf3Tfap_*!HKO!?UZ_?;^>bWhshXqg zd3uDT+L{9*uTP9CEM==ZH>IV&)#UI6`9?paFp%mYaFVAzdF(CP9=Q!>;Dmq$)7w?b zw!7<9crI0+Bo}P=hlJA|0lL?hGsu`-)74Z_+e=*=?2j_Z?T<@#PbOKs{h;x!jm@4~ zi(?m(hy07(;Vq9vO+=cN{^&&Y?kKGoY$j9hUpbznmEiq5kE~34`!(Aw#>w6<1MYZ^ z+E5IW!|9rKZiZ2d?yWxE$m`So#XU9ztY5Fjd>1dYFy-UMc8!jfnxA(OR-^vbul}fz z%bxBFJ~8f=cW>7ZBtHyf^RyGF0ogW6<`yJ zEBDNXgQ0s6x7+hQl`q@?mh^yzoAX@6ku^FdCZ#x<{42J=-eoMAA12bf-6V^jaEDd9 zCw|ut$5qA=?QeYz5Y3KZBEKR}Cg)M^G`AZ71D=UJUlog0EH+^#WiGSNlQeZLeNovc z^KZeV8su7 zZ8bnf!|V{4nMgJ}fvPu0V`2yB%tZU3h3=q6ZfLp}!+>+rw? znf1lil}~mNa{88P->;A;2qo$Bv|vq|BIusk$Ygi$>s=psAm}=*+gfpt&Z+x;MEL+kY_=_c? zZ+3Y{$`uIo>RxG9KYl8eez0ei&@TFwa)CW(7S?DOA=yz%hJ|4@aetXyryKM^vel5g zAs;01-0;KBwzbM|SFx@EGjjcTnvqKmCIOlstMkYQ`AAk=4AjBkdjV?l5u^3w)YTH_ zk9of1xjDpm6e%w)qMY-WL$%CDxVIN$dfo8(5c&NvTrvBWlt59t0g`K5t)n1x9AwjNW>*vbGu z{IE7w;=Wj7v5lBE+$$yCXb&%9F@RwjK)5$7F1FW4O!n5wph5J;np}5J?pBR+zr?+% zh=K$8O{~vY!FAm?h2^qe?^`*K?ORk9^?}P5^mS*VWVJ7a5IK}Dt=?2<#PCa~M*Vs% zr5a?gMrkFN2<92;!CSswO-#wdDe>WuTOJi&*4uZh^BLaMy|ES4R8`vtznPJ&w(Miyotu82j;ET&T-CAau+_cW+=Nrc91=;K*Jduq=;Ky%C-$e{ODq zAp8RYPgi9^oi(RJjzpp8n$})~lgGR$-g!o{ zvRfUXEBq3|?>TQm?bMWggjFuge~XJ-UG5DrxsKAm?wu-ZE;RH`lutXqIi94&>r&-HrK&Uq4 zAN@us|w+OLil*+Q(FDMU5d z_pU$)`I*Gh!~_tUbk$VYdhujd08X-+0di$*(MFld#&N5P7Ryd|RCV0TcEIipP8eu~RlaoYesIp3Jd0&~n^L0++}AKmPkWJmd9145s`8oG1UBA!y6SMGJg}ipOeyh+9n;oUS|uA@;XqvvrNA=P{9y%KfcD8F23%IupNlW zo^Ft{ZTPlRUyePOz1V58TAJAYTRHv4iW6vv1{6gFzS_vaT|)rwoPvCJjggxRaHz4O zmeHHVJS+ko9hQ#un5?*NGpn2lZ^XrJFq}mv*P=5oQ!_PUwZ4m*n44JTrYu5wWftp& z$X^ZF@pz_DB2=N5>NnKdRWjQDdQTGhHuHO#hmUWWb}9SY%-8D2g1bdUMTiuxFXmxp zWurBQf#}8-vhl*spUSb>!o!DZ9j=cI_v;W}Z>s9iqD1EiXZ!NM_y8}(rR}xp_c*x< zzdh@J51tVIkg$D*MVCJu?b*3Ik~?d0 zhnx`z1wC|EaJN;_1_uS9OLFp+>1dFu{;oqt!yRh;C8Fu;c8kkN6MJf&!Jy1a$)PQ3<=8j}j!TzJ(3cwT`wqNE9L9&Ip$ zbDVS3Z-_s~aTf++1~nogke!bT5Z3cTp=RP+kwqgo2HDcW;dM+MCA_r()IvEudWfCD zLm#&`R^k>zpaBk2Bwv!^P%|0aChQTSqO3`-g}xm#kFSm4tOtnfd~YxXH~JM|((_T> zw3t+7S`p7iay0F|azi0AbtT5N)5!gSzh$n1enWwEfGrPfNS`&QtMx=%`=Y36`@py!cfgh7G}4DC6%=m;tFdDrw- zAC}m_Q`vwQvaaGh8$&dpf=klPANis4G&Im*=hn>q=<5nHneMmJZ}$mt*%r6;?Ns6) zCNZLM<6rq@vet7ksX51S3mwDE7*mX9x(&LPwh6SOg5y3sFnCQW=`y7q#xf$}H*I`| zd%q7-wLMGT!`IQdTf0s?2tGr)w}IwVi|k)Y5KU@>lT#*@sPLhE^V<^r0YOm8{R>qF z?{PM9=XYOpV?#v;fEMa5D$Oo~IG^7(_g`}D*Q)k$&wn?poYZbfkiiABNWPy+t0T|N z;7fSi{x}o`{8(*b^xd@u%Vj-QcrJewTOr*c(VS{6_f66QfBoth;hbl^zORuSzx=(j zpWbWKO~E&NS-A@@38ybGG0Ntoe#tFm`B!jT0i(MGLpGAJqffG!%{&NCf(tMPpsC0C zJCS@v<~;Gd(~r4@K_F%J;EME*O^p)AKHbWm7PRm z#iRMKGd-OQG%U*CjEL-xji@SRemZ1bvKt70cX%&J?DtVw8I=giub6x|57r!bwhIz3 zQb(k#`0}sf1rczEzaeXXw~u}@91Q~H-hFoer^s6)RTui-x_D7Q&VGz!BA61$dr=Pv zFE949(H$R=;2I=!SWSAv;7}P$s1EK^F&VsU{rGElku{3eZjNP(C5ap;Vtm>gBG#A{WHsQ21X*=zp83 zb0K0~0@JS$XeaTm?r(qjhobpUbWJ~7-^b~CYXW{w)HgF8@)mA~n-`T<^5$2g-5b4{ z9Yd8H;ZJ~U%xv}JofWEseZrI(f$4ghLha6S3KT-xV$m4lF1o|_7$yo5&q(AF+Ys5C zlXgD7qs~%7%l*l*iM1zxsJb@PZU3cg^xgR;+Uc<4L?``-4g`17I@Yfj(D5+r=E$$y zzT5bo$8&te(ex@g6_4=QPo1y2#*|O5P4`smc20|)1|g{+ztGRMxCkk0mKY}K=VPSk zjlT+WCb_Tr2Ru^0G}O=xjNP8b8}4vRn=51gN89;6dS6F@yOeCf? zHpt^L7eTI#=%251SHk0DITsurT@y-is1*%72^RK+t{>)#eG6 zMWI{n3;wRiTTW0nx$|apw%%=1G(0-GXo%+|$MdIqI;m~+k=}94h4ka``0aXk=N0l- zYTyef&aob%!*auCI-u8W!;-BRvoG6R-TH;zMAXC0mpLD{F5}+Bsu2FZFf^%9Q5(d=OsyRkE> z$>9R-=e8aqy(UPNXx)3~<7qXicz=f9PHnwO;o7+`KZNPk?{F=QfDs%ubfVthyx5?j z{=UOgErXCW({_i-YCSMc*=m0Jh};}K^2zF5XU^<5Jxac|bTY~P$S3`beOLoRKse`N z$Y|h-C1ls0OoGUAJPm1WwA~EKuj?7*H+qc_O(7Cua!gnZ-%=}ydAZ@2Z26ch z4r{rO*JzFGAt)qkc?}?BtW{enVHkY+y6vrOmgRT_2p`z3*&g`$Ah{ia^B#b}KG>D8 zeyxvF|Cp2pU;iFNT+^Uf67W_-;8XtGl-YXL-6*UV5}%NF1%)cgG9jQzN-oFB_d2fA zB>3l{2%&ecThVbn*J-^!kf4SD$on3r+9;G4wFG$l3fI?FPrzI$xt~MpL>!U~qstYR zG<4`*`n!IRr@B~T$1rYYLrZo2>Fz9IZ#d)sA?%lKfK1ebqJ{DK9-)HgmZE*bR}4l! zffSqMYFEpBbC!4y*#X(DwxaST)BM?Mjm1j=<7YLyxq@F#5y=rkH2vbL;2Eytt>;HS z^SMgun~4cQz> zdN;-aFO91aJ$ta?x%6;hmRgblk{FW7g#~=$MP~HDLI1S*+xfYWpX!B4(EP z>n4lsk>zn=jaWH10<0U{?+PC$&h#EAgjk7`+tyE+JIZ9&jV(K*XRaf9?vg#ITS zlF1oiW{=iey25?4$41z#S85o+D$cI){>pD`jc9*s+Tzzzy&v>e3W&q#<34qM+S#J& zi%z{RY+GC{G2~cZb8cE_T`f_D*HP-y#L%y!Y%L&Lx-Ssi{Wu01WgbxRn3$~h$Fx^+RoCn~YXV3XHxGuGNtziVf=#gx`gUM;{YJ7MkZy-nBD zn?rt)NU9a)FqA+bN6(MR#G|tJe((p6qlUS0g?r;z({7VfshMGGTKDdNRMeP8?$3|^ zn)3FO(KJ{1*)gw9r~6L_{8J6$E*%hbzo2$@Ozk48tRd8mX9~Cf{QOb<^9LXA%h1TL z_n&0R+9WRX5TQ;YBS{6z?=)){RNeK_2GpM^9KTQZqHjFpv9M}Bp|fZAHQ&;{%=Nm&sE0UE6RUU?)Wi@U3wVs^^|`41mYqM4r_f+O;&b5;<iL~a3zBI63SWzZP8aGaf zi>X|GM2JjLpdy4SBn@5cY>jqF6(B`7S%>rdLFFxET!Kq^DZBV?S~sE!S!iIGV2cI{{A?uKbrb>qIvjndmvVlb8YQ-cB0`S z*}>;5+UJA-jyy!0)jxj>eNMbkP{={om9I5I(##XEQy$1S{??#U;3Ip561l=ggj+{g_E6AO4fv*ZtEAjoC2VtA0!jMo&xC z@q~`|1|WQa_h>}4Kq<|<#|;FR~38$kdyqOc}ILe_<)xc z>AgD$_$g)E5^gp&bvE9WFFC-eEh~0ELey-+yIY8*k4XVqV(J@Uhs8{HqVR4x%y+dhkG;#iLW54= zxE)5lTM6X@Zs9>uTL3R|Fku{gGFlae)m4Wptu9fhlUp{Pv!nFvyu;NXfeU7_8jo;$ z*6~Q=bx&L6L2fCkwf*W->gJs19lpgaVxgv+??BMeM#yIIyMaD<#cQYFx{9m*cpBBq z{b_yw)lM{V4xeqfC0%ZA@`osS_JwxaolnT<1TV;2{2X?!dnrT?h<4@~EG~ zLZ3*E8Eb|0*IXSPV@|19e^-9|az3%qV_P90xE_bP@gj-O@+*j<$bc$F%ZDCrnQz`pO&tg*g*nOG-0+g2IjGa9O zWp5vkR73s3elN@zp)4{t%&O0&$^{dBIiK=%O&>nT?s+Tmu+7Nsx4dHZkZJId{ixBj zS1XJ@qU?-ajpamPW@u~4YQXF>+T2=eEu=WUMM#6C`m4$YyYqSe&{*}%CEL;8@QRx8 zu%vNfkLgObZd0OdHy2=8u_hhIu{$Pt8@uy{G|sJ8%9vpF&TIBZwYga9zqm;{~7VzGbF_}(ijz)EmZU764Y z0$I)bG1yu~SJ5z!42Zl(_;N^sM&{x-_%&P6@>Nu=B(bd=Eg2lc6E%Ik$sfj$!w^ zF??UwSV0%}8?J+Mjcn=k3fqnvQ>XdyRXT?ws_9!|ZP8K$)bi>{xM)^|#>u`RJPHO` z1)!9RRnBjSdfK?m%)00FMT~!)|AIve?>ko~FJ*JE9FT@@?8y~md-3XqOQiZ=>RUk9 zc&W8o_r(6s3h??y8tlIr#hd4ia34+ku={YEG)|09>Mq=rv#a2z$2oMX_4KjAo71S* z7VYjSKbm@9)Q<9PUfnWhhK5bra4rnS@)U0DQUwhf*ev&lj0}W?Pz}`B=ur$LMVZdb zYs-Qm<=&1A2&(ho?5g#;W-9Oh7W;91Zf7%}@oZst@Tb$TIHGjD zq#G6*uj+Ttfs_x_j{1Zk3CA6kooF3y439WND?@dOR`W#bY#-G4zhvV9+$l#3?lKM{ z+{OWM5QPv(Bf~yXw~Dq7+=kXyyN8Y~ZpjnJqu?Nac@+}HMCK913FE!c4xto#47 zuK!KLvag44+=WONXcM6)%x$Hw?qGeQ>9cYB5I944dO*G(u!bduO4>Zi}@neqD*5r#Xk9Wjp@`ewRaoQXOFwQ3v$F0`;8#1x#rt+G1DuPq=Mi-cuTS=jcEcVuS)6fG1pXdTrn)6ej4Srm3zU79skRfY?h{R|p!z)1KMjhztFwvPKou z3<#S+kW;CTzu%iEnR-B$ymLyS^jyAeOnxjyGLIG6vqlj-=S4Jt8WGniVqRAX+_j^x zNb=O0$j{OkwAy;}9ikqJ88J_ZdXbSikUcD5zW_wiq~8HNxWk`=A&lbOYhSa_Ev70; zQWYSK$9SmFUmfI{yPDtA!uz)ByevVO6jD%(ho`onFJ06?N$x)$WrK&evFB#KG1j)! zF8dk_tZ4e~;Y>U#Q@M;3WgOl;T41E}^JeMeGwHmXZ8fjErUL$G@HoC%u1D~GQrQPGlHl%BEI0M8=0wmZ2h=T;kCE6bP#L0dL1wR6e_@C` zpUdI&h9mIpp&W1ecs_|vo{azsZ#kgWy$kC|@+FD&!}E#-RfC>oE5p1AenH8j%G~Mn z>Mfz2GM&-mOHy2mK*B%*D1k*!9o~FE%-~8;JffjNy+&P^3_vk))^$F%u&x2J2EF1o z7gHyE_R%LClfoQ_kWdr>c(18uI}xwZG>&K;)k{XVr>6)XJ>L*+c*!OYLC+&ldWy{@ zglp$&LquDf^N3Y@X@5*vm)HCEhz_cb1XpM8mLNf4)}Ko;hrn(CWI<`|2mjanjag1u z6OnIbUz#SheA+3G1!TN5nB09a*V82Dz*gN}rF{!|NvV1^c21*FcP~*MVweqo4ZgbU zz_1lLo4tWabwZfJ%*%L!2URw1gkOyTSeeq9Xuw5)mhQ$ywXKnq_**Gmwp(vAGV^z@ zXC64?LRwEfJ)}}lTBG$>Rp`1p3+g8`Ze!Z$76_?<0f~lp!q?mR;a{2}&98n%S_I{u z*Lf}GgRe${`&>RIZ;w&?Xqp(P8F>W;s{M+~KA{D9hVH)cudr*MxEzepJ@2itK}-iq zL3wH}V)fof%eltAu+=?_vY>Z2`D&3<474<-Vy)qa;t}C0{QZzARGfy=l-t0kc-8+! zHMgExs6Z{oY=Oyukn=0-Bf!1WgtkP;W`m@C=xTy2*rh@Wv^z+A>#W6X+{w7Q`B3nc zJjc_Z;YB%hHuH3mFq`xgU)#Gc8)T@)h4mX&8FcF7%o!orzkvVC@Nvp`D(~?)s?pLu zfb;2lWQ0#N4pedK?C8ec3cEROSF980_xYU&QL8~vS3lJ$W`?yYuW(4dJk`+J#RY+o zTON=zbD(yFH+EB`G|bxX{e(|p**9rtYepLf^BoWSD=VI1Ng#*ZK;3X6!w(l5x!vy8 znL_{Z;{JwFS=Yu8*ZESn7sj@<(LqQJ?Sg9mZ+**j@#R54HQ$$QmBZPg#*eOz-2or< zK^zGmvKcDxMdWP$MgLU@Ky_x_Yn{=SIJ7pu{)>q!b9%zZvk+w{3pP)hhS)hgv*b-hp2Dbjcp_LxAzDs#GtJS=Hg+EpE2sFv~jeuHX zAgdmx1<&ATH@!c&Xd-HUH`E@#91}hK$o3~NNFTe=1*UPKLY{GFOuPS>xuqO4jJj&n zA5w;)6Li{POUUydEeu1RT22iG7+_JF$M8iUgQw*A3jng4$H4RF@j7&%*k&)aY6+mZ25mKq(M+*k?0Y4CaV8)B@R zKreSZ0DCaz@?GAyAtgy>Z|2)#fnBVsHUpLrH1e{=mLa)(&CCAR{&Ml!KSEf71Fj=; zMKf>CIM1hq$FO>L?D82{S&!FgKBgG;Z?*$!UlN009U9RuE0$=Z%s7>*8LL)qo)KeR zuwJ#4zU_@ok7xT{8DE^EwJ)|$`FJ3hmJ)(q6$+;USlomKZm67|HQ1e4Z%4He$hF6L z?~VX&uO)_^#CKG1w*syX^~4#zVp&uRP2C}$7tnU_c|Bmi>pU+Pf_4`REX>Qz+e$Yi z2mx?OMgU}Igg;50oVpj3@<%0cuyn-qJng{k2Wr;bZAvc8Q4WPSSIP(A_xZ$`@>UN8 zc$588?7b_OJj|iIydJbCv^U-qpZd~3UGOKcQGJ7qv;(Wa767als^#T)#nHTE_PL&> z!r&*1L4`hq>5V?UREXl$=E{b1!{p7xbp7oY-9kl)*UugIL_=5fQo(iVKeJvJe|QY2 zc-|_Xd|4E&ZTpD}ikE<6D>@UsNoZ0Zx@8MB~brA`il7d|0F6x%oj>%j&CS4X|M zd#HYP0y{>GQ6;9Nq+}?{Ky&@+w+sXKg5Q_*CaJEIv~Zz4_`FQ0K*-PGXTF1Z)}Oi_ zfnfm1D`Zb%;qu9Ulq=6$G-fmnW)$Anl|~pkwH1=pM4P`?8m_}u4?h3L>bSCCeui}< z!%U(b^u8dFPN^-r!IH;&mHd1F6X*WsuxnGwb)RJv1s!#v_i02I=P@KxTWUh(0uooP zMewN6tT89mwX@-E#Lvp@w!|X(LqoCaUWHD~=l$+`;)btrd<;pd{H&S;$1&JVeg4i; z>%lJWjnzDRiG)HAU9?T)WK3*FbqX7f23V_d>#LTt--7QHQ@mSZJC9^y;{;o#UpQ%` zY4E81ti%T#oprq$N(2FC2m(J}7!k{0`?!ni&q0~S{mgGXKr7x;$ zB$2x$fYXF|u2FRQ%`}-rFJoN*1;}c>e&9aSAQ4G=U0ruA%+4mMoAZ=~sDSlEwdVNu zIB!u89?CrvV|4Gc_8lK(8pr?;v8G+Af*tbdVs!yfd>FIG0jbS>ulemcR_i2%p-B%` z7b|j<$cx0OYU|FcL^%Ee*J`K~_VFdWUX4c7B(iVpl*4p%-)1KHdp2))ani{;rS#MU zYAe$C7~SQoMNhF1_kp!Z8#&BO^1ifh5&%2L?cG#Nb!oT zm<-L{1zhLC0N^Fsf`{@;$ENhPexBhMO0@)PzCXlWJo~29>#u6f8+R|G z3Nq5~`qjqn%71gBVadG+BeHygK91q;D%1{V$9~)@zyO77^Va{*3p}7+49&iWU3ffG zcR`-tXjLB0XP=)5;0+QUJG%LY71oQD1l&#aM;lJut0>$*Bm zxGX5Ux%6vtqF>tg*)KH%AKTH|=yuJE>dT1!6B^hjx@~0O)0l0PKF_+n0G=Nt&S>YL z!nZh)*3KEzCOz4j!vzbOuSW|Mu4;#qLAKNtlMgCHubQ`c^)d_#(vqWG7Pwx1nAbeq zMQ>r{`pgIxjq{etJ2J_eDdB|kEvnMNCDjn`v7+nkqh|hu$nxzHPTb8a%eu}hhYVR8 zU)PQLba-)n4&DiYyk@)~tWkq+Kzt1rY|p)Nn*K`XwO2WXZl#XNf}1oD!f1GTWfWLp zHdL-xOMOW~`|p78)c1^&&awZmZ}Wc>osdS((24&!m;eCYhZPy8tM;(F%OI3mHtDPH z;`|_Jyy{ksFxx&{`ytEDWY)sdc1|fqjO+MUYTz12jmMr#Mz~F!Bc3cK0ABQ`{Vv$x z6DEZ$ESgs&%m!Vkc8#yr?}_wkHz$-m%;s-?mj-M5ayEkT({`gD*`23lwIt`!JT;J5 z^E-g|a||eo)1I*?H0QQq>9zDLH;*aLTd12YV4K1LY$y1wyIg}}G#%48yfNMKH4yT& zDMfY6tB>*NpJlAQa6PU3K5L>Ze||7Y29s1CWjw8@zIFtfzXh*F7$V+N;cc?i1tfcG zI^9wzPltz_#jWeUv;E>cvdW~J76Uh12q(@}O~Y69561{QpGrZE@epPHyEKhJAC(j> z*A|zI;XL8lCG+C*kB!G7Izq7cp7D>Or$bJl%)~g7&cphJ=Qf6MB%z)h zAFF~1F>pHf#ti*sV1@nW$a%3v?~3*Fn|HW`gy3pGBsx}sR|GfRJ4#aBpN;~`EL6P5Xv=FF@wqX@9(Jd76hN8;=J zk$P?N{1-Vg3e9Pfj1~0j*Z9(gDC1Q1cB>)tEl$4OpJSna>w-0(i8Ea2VyBA}xmkAj?PH78d$p|W8vce8GL&j#A42HsTbdijD#b#__|U^j4C5Uq+KpN1ip*q|k&R)4gn*hR*VVL|cguUf ztBb^IoMS7r6lV@0wP(WK>0>_;=QA5r6ULWVHLINKn<1xz2W~1uPR-w@&M>Uk6YtJo@e=$ zU-3a!YATo%cXEE$?{PxU;U5Lrx8n;ps$-ZyAp`m1mWofXBjL~&!q#!g;TQ_M=xFiW z41tezB}@#cKu1()PucpWMsoOeLof!xS({wbTWSDs|K-zG@L;{igJ{S2C@=7j(zD}!_YZ=%j#ig>#D4_ZldgoHYqt;76#$LvfXYTQ+ElHp= zWDfTK6dURDTdN1fiuw0Ii_h2Mu>g~BBNo>zHU%3e9@-_lcdGm8YjO}d)gMfsSyhI? zYv?VXI&*wr*(KNGHO|I^ zok{1zZatzVFj4jM`MV4&vZLOdy@bH9OBPTBUMZ zrtDaoBd94$oc#}38PygQ7$CRI9=wZXDUz@;*`|~WzmHVkE;wsuid<%dw2V5<&bd?0 z2P?fZZs+?$_NVU}8ASZo<$#2)oD&_&i4zc9WWCus?iPj zfM;q3#zSPjnl?Gfxob$|gxb$QqRxFpuTL@ z=^@tiJ1;uv{kf9Bt9w@@#vXKb5)$n`*o@klBn=>JxUkDAJnQT2x z_c@UsGi>{vwq*zghLwY7A=vZ=pBKFrUxz5XhvMNLz)LUnE1l6U=;zX(0uAY+A>mUI zxo2|Ue9YR@!c`OW$*Y#CQvjr(fXTS-Q{7bAd-F`GQ(W`{0ZWgWQoUnOm`#`vcT)I` zor@VWhS>sw^mb#Co66=7?TncE*vcawcj4ANQkMs<9v_i@x4__@Xnx*?Q6+`?poLZ) zPStfhoYIfsH9OBoAikf3h2>Drdy-(|w{+Z5JO!D)a%&QCS?C2~-Cj_?NG!Pds+CPk zF83sa*Ar8sQLJvzZov2;H~gTcEOS-NmM6H9_BEx3_gqxw&IC@T*buS(&WndtOx{I>$y;2Wr6 z5FLQGG8hfm^XE^AQrnDQ8()Yh>a!f&a4@sD*lgvcWp&jr$7nAGP7<`sjLYIz#u=VC zBCkIo4F!jVfOz@m{nxY)=(V4cm=+=g@hG;@thyIc_D0|A{CEp&Rs!_weJdzt0!S>? z`wgzP%owMIv*Z6~%D1@-A{Bh!mBuKd%w=|`=w5y24VZgR6MJbUW~u6_UE=XF8{lGf=avK*z!mV}pMi_mzMNF&? zQb%Xdj<(C7w>2Os1}eq;LF+)Vs^h6O`5;vLsYjxhan(i0_ers9HmW*zL2YjW$asMo z-WcnI*YNvBY4nLQcGH$_lZvu^vo=!hQ7in9P^(zlMPLAr?Bcq3bdaA(xb?ZU`|G#R z1HD-)uenflmi!0Q_f+`auxwpf=%POy^&2K`{wuu*qm#3b!*8zA^Z}yIqxjLkLu2M9 za>3F^7N={2;ZmyKU4yk7{Rt#h$cdODpE$!x#D!{^Oho#$h zw*iy!^IKa|L&9rW@oJ>JZ=Mmo6~u}PH0d0Vvz$)LRmOzib5Dwx(8QOWMBB35d}X2w z<)(#3tew)spb@wCEDP@IdRhjhH0REK{;|b$B0}0XG-PF01-O@NA7O8_mC1b{nAIMG zGC+ANKlF*A--Y4|ASm)`l40y@rXXV+#`8jSqc-{5k=#69ht(B3t>N0A_Nr_95;?Eum>?A1 zri=eyY_;dh!9yiSB4_|6mxy8+<< zD&5yKv(EUpAFPYxvJ4DKQHEh^GPK2m>0$sT%+9XssB&ix34i3i4Yvl;Og%?HnBuFA z0&enc#yCD+YHDD@ntizEgBO@EU<^7JAP5ZrjiTcx}IjW*c}6eKsd8W~^Uo zzfhs}M>33=eJ@S_SJX}J0I6h{w-SWN?c7;TbTMWN)e>8I;>kWlz~Q*f52xS%v|@(6 zBFuN$iE?Ni`;EQMLv=T@`C4v3mx57fKel#9_yEM{e;IXNrUYlNnbEdb{;}w{z6Bhb zDc)5KIrq?z$V&7cQIc`~vHVawDu`5blv2P&_rGNKcg2Usi{SxPGc~usS>!xfrmNW< z@yvTuc$;i2?$2%3yw{pXw{6ebGHr9!pt<2k+Uz`OZCpwgCzb9jV}CBLkJ!)c6-+Hs zV5m9}T~PffcROFLhMYn+@0(_7a$%xcCJFxVkQsl@L3*giPMrzok#$=&@{0_|jNl*5 z5uTO)5{8RKC!Ih$Ovp#n+9i}T&7+Ix1*8U)&FWh=bpU^1Gz` zZR})3U_s@PP6K{GY(Q=F4>I`J`t|Lw?qARS&>#dCW6E##oy* zp7kHf;m28!)d#@#h!{a~x}~3mqN36kvTI|)4VvbOzKDp&2f$Tc!N213zD29GC&u4x zqIUB?330HjaUi5~&y>Eupqlo%&%K7VUUq)Q7)EPwDO&p3vPDQUXPHMGYfTyz_+cx{ zJ5~R-t)@%I?czr#7DIr3=iS{RSl1jRL%-0RlDUffNk#p^Ay&atQ(Gt6d&`Q+vg(P5 zKR=HhQ+pLrnaCg!gV@0J4tb&VU2sTz)iudOK$@ped^Le-QNHWxZA#l=%@^Gt?_98V z6z!{uhVyjWLdbfF?D!J?aeuqJIA+)5WX`}su+fYA=~ys4XFc34(j^krw4QtV-^b4q z+tbI$UwI2{^%ugJNGy}=^B=#4?nUjcM_E;gohlVP1a1;jM?F%|L^S&_5KM(Me8}B8 zJLQcyYS^Oi=(_zBGkx~Ff`&Y{FvZQ6Nhwu`6<3&~F!jY;maymfzmvR*6&pX6ze+>H zLR@G!Ru~kkrSt<)lHTI%K5ukA4W`s^#Sf<{CYcgL(hZzukfAb%8s`rMQxSc#03=to zKGIR>xSe%9fNHaVk)dP&I$qOlBA6$-ViaFPdKBIvJqkGZgJcUpK05;XhI}YJg@RI4>6A4@vbXb{ zhPKiChXmHP7zWc4Pj+u1_XHAHHUJ^Pu^WR45n-fY9+v z+D%)?w6dVZo;BPG(b+wLtoG)AT0=TSF=Wpu*L>7w2}#MzL%`R=v)e~ znd6Lt6aZ7_U{ZaK&?f*3xlY*A>5neR+R@7D^+eP)B+gZf{UUw(oqTK_aaWACZ8I&pvZ4|7bjUG6yvdYcIf39;`d5ScO zS-%LgnUZfjMn94aS+TP!4@cT0I};zj;Pd96j7j9O%vxs;0HC@=o6F#K0di{KC?g=2 z+AJjqyQ$+>pA%9Hiy0ZxWUb%)&--2fR$q6ZQ`Re~yV-(S- zx>I$I72d8@v3mY9IzhBCy|x8tumE^Xg8;zqj&IbLX`NI-BU~k+t75Ru`n5L-8)y@Z zW}7U?a91!+4A;+{eE*=Rq4o_~uO-&icL0sC_rQasb?ZxfH6=_6Ez!W#NWmhNTp#<0 zBC~gD*|)_Y=R1Rjn+}5Nc@vhe?+hMXjlLGQFDNXb03wiy>~ROj@=^4ElGL8TXqwKt zj`*G0fQugQm)_@E8@=K^rn&YLUC$<#=qEJ^AOg?A|VN#)^(KFTGGbut=3rX}QM z&=(Ga9tu(kg*UA4QEyUG20%?OEp+CY7ZVo!jhkTqm1tfI-$1R+sa#Fe0zgDGPeg-m zFybhcs~`LpO264ehyd*v;Y;4HDrZ&)i7n2W>I0#J?i>3M0@uHfNPj^M zoUZ87Dey)qwn^o>aIi?v^3{lEqqK|EE%)cETJ7tivP0Y4`o@v1Y43fzw#=yDDyNW< z%I$r=%RLDXr=~P(Rp)E9tU*dN@^K*U3?|qpz0uQ!>Go5$59UD1r`&eB{7IloY#!af zzuY4K!J+{#4fE8>OV3K11HlE9E!Ir`U%Xd!nnG^nmT+sSf&Gw#Lg(|0MI@@^OYy!+ zN$mAOQkwZYc2WlmJ}b8#?fz9w;nuR;vH*B4u{HqC)<`gw-=y+YL4T0-7}chWec-9M@&iwRG+ z$qNQ5`rJ`M*An8udW^xJ*H|{|bcVCXVuQVX#!FFaW+~xaws@z;-f95A^5EmUe`IoS3%}gn`&i2y@o_e(I`d!w` zqe+cY?d}FXX>-$tYI^{LdNqjIT++AaV(A=K# zj&e$TGh2Xp7P}yDOAz*W7#jw=B-KSt!%Ok-Z{1_Tds^v8p+g$5qIU#yOPuECRUPElB6{vZVBCmQB7}*H}8` z0J%9o%KPht-;3~KM!P3oUxKc&%8`6r6rfwzZ3R+v>pmYCnD?V~@{D=FB-Y?YpS(U; zHnq{n5IWLpRDOX$2f9Hyc$eEcK^MYBUf|8S*wxrE+t6@P)4a4pN=+WU+0EDWEURrH z9{ad6_JpKdLj&YdfHX4$d)xi3`}$5*dEBnd9M&K&-0}6aX#pfQ;P)F+2btKo^BR# z$aB}Z4tC9*rV|e*=P}wv?f7@b-tiiF<*hwdhU5stAe*Zl7HW&PmQw@xyoKVkEx&S< z4O=cm+CLfOQqBFlRQV|`U36wGU9WF|+*Zn7t$3`60?ZPvNW5%-n2h=b?>-WtG*-^I zT);1nJxhphV(kE59i#m|wW8BY9(h$s329CYm~mIPrcLKK50;av$w%gI(M_2w84Rh~ zZUa50%ehENDp+JAW)CUuDK*ZgwaAYrNc;jH&AFgf!>>0;&{eY!N2*@1I=B&%H^bSJ zhdW8#ayAF`l)t_C`1lt6ZEwS>>Uh(i5EHX@XJutF;jq4YDRZV@KV-##X7Lr>=B_xo zX$1S+F^6$T+u!3~l%ePDz|m`b-Za2e8KEhXwLH-S)E@E-r6TC8!`|$#|LXQ709i@o z19-KRMUy7tH7YOd#whQ%Z@?)QUS&%~5mT*SuV1*%Uo42KE#w|fTk4Xhg>RSG_P5}h z&d7Bc(=3}>+9a&E`Z?Y@%)j<_D;y~gQo|^h`297jOIT28V`kF^!}vfT@yqxGGpV7h zCQGGq8H{t6I-M@d8<@cNlKE6U4UcVOW{lY8%Oy5E;{YnDc7M*`@x$M)%^DL@tHEf1 z@U6~7PIB$Qdlqqhmg*cPX03q0ndb{?BDH?VYR4^Z*c zn&|;SnR7|gk?EhOxB(q>TrI;P!%)%{yI(>Q!v7h<_j>ep?fr;*wA~l_rLA)>Mc+u} zU6=MpTX(l@m{I#BeIIy_!ZqA_l<})Pv)UEssrlD0X<@M$fpYY^_TXFY=y;e2|JYpG zU;@*vjYecDp|3_)fBF74o1P&ALKz~U$Hb+~lj{NZ*wc*?s2=dr2Kn56GT>e=Y4UB9 zVimZG{evJ#Mginji4*Tk*YF_o>T=chbL4nF$}lUCk>KPACFkG)T3leh807#LAfe@X zMB&GFzai%DtJblXL-}oSlz8?GMDmyf(hQ4TdIncHgnyT3X8!BAe>g?vjeRQ)wAVJf znJHI4LkymJiFi;4kjM#uQV!s4|BJK~Gn%zbMakhxoiW$NOSdN4EJuAu&02f8iBen} z-@dgD38uj-v?&~%gy@O-``2ywEp$uT*gx_f$i6V>+Of`kOdZ6^UaC*DR;zNFaLKZq zZ7D&Lo7RI$9~t4TV`ekKCJg?nt*$HexlOfN&Dk!j{R)XHf?^&zA#eVui42+9W>-7) zZT&6g)I|HGu*FKWIBYGFn1?;EFKB|rS$HD-YjRFSB5Up`GWh`WG75DgE_FCsxUHa2M0vt=}F<}v; zKV1R=rMfIowy_F#4u!#xrjIIDq1Cf5ABX{mmv|I?t^YT+npP3ni|(*eVP4%F zE_XhTc79W)GNsq~ly13A8CD{=lG^nzv1R|anyNS}Ws_skN~Bv}iV8o?J<+*#wSSOW z+G_BDcZ=)kYsV+I_REC!^Zf(%l2%y2o#l*Csbdz60 z!o?vSt&Y!?7(H9PtGmz4tjF}+IM^ToT#x1QNbjiLsDISd)aOGtv!EgUDyhM@mcI3m z8s(zft7pJ5j{Fj{hK^tJ4XdNN{5HlHs~2IT(4Kn%jAer;-lw&$I~1I2QT)NC_0E6D z=Er&mI0QAE1}PsVWxcLgAK+=uktG+XOwQ%ind;C`!NCaYQ~E_&JS-ZsFJMhup6}zu z((bm6Pf&mp+HhG~ZJw;fE)rLlbUqOA1@}Tef$(TSRll5z-EKOo(NmJp4KecF74VHz zQ|YB9CWUQ>J)W{yqmpO9bD#M~1y)?T5^C-j) z%XciG*yvXeW$kf)lT;*e+Qgg}zRzeCm4KchJt6;br05PkcG(ZEG9=;BW(JoyZV%Nn zQnxp`td=8d^m(pKsi4?Pv$UeFVCw-54%oDHSRyJ4FCRa87zUOTOZ@^b*6;rB2qXuZ z9NveFmO0W7N%#I!((vmY{+QJG(955hWq&4joO3*AQviF6_1v5)Igzyne>Y&EUKq>>M7rn z_4*(=hFjc|EBZ)#$CKD0f%IA_tbdydxUGu{^fQaik;jBAql`dxm1&mDiLl&D*-o^Q zwaA*b$3t8zNB}m!s3!GgSiMR>uzgN3_0rGG()0R1Ep5tWkye>!(XLLd(Hso`91pev zX?)5Bz{(T{&i8@aj=wLLbHTMGr>nD{Fd?Y3mR!+`Nla~W%be7MPpb#W8kTSDVbndD zG9~Nm8w)K!-L61l%W=>AlobHv1YqUQ(X0r=J-AMdw2%f0CAun55QkmUJ%ut7I4mKZ z{lOYP<&LM`gi+t`piXQVnz(B;nbFyn<6sOCRLseGOJSfuujH^w(*DQJm|bZY`f&`|$U)WrF)Z;+rspQ1_?@6l zoYOthyhxUJ&_lT^Y(B&Gwv;6Wmz$ptxX@wV$AhP)(3BqgX>hEWKK*VR(fORw%&K^N z+nK|bC6v9z+2HZ^2QN*?n>sctO@vsI7O#qEMpPRI?4JgH*Hyk5APj>V_`8W0{RZ?( zp39bI0!;le&YE8U0FQk7u{|?0=;+dMhQRG<$>3(0;=9k24$Dp01jLR7hQ5U(5JMTp zRrUXM48K4^xS>?V7PDs~^qcEr)Y2l0cW?9jy+W8ty|`rK4rax6c7zuF&Omgs@CV(h zWB&Sm5lcit+0fyv^)KG@vr@x>r-osVt!+rqmf&pTyDNuWldj{*htz?3NVjC@RH<`Q zGFQ~*1(mrN!k*fBvdK|a#6L{3RU6^-xb-1_rpDU~o@m@veIWa(GQ@mV(q1F)&Gv1w z55WJTxDh2Mm7~eQ8a5z1bLrP%!zg#S2>~G)O6%8ME8s-QPmH%^N{Q?lpWiTys8}>* zAB{hn$PMg16sYaZZUQ;~QYzX&@k&4${EFo%61VhhQX zkt+x>AQEL392aQiic3zwGg0p$+l*tP!RPgT)*^l3*4{G0D8VV0$9(KAt=wIcS5n$3 zK!ULK|4IS{-#~#=!t7iBNTTWcc3Ch|P-{gLz$jYJlN>QF$WWJ1Vwe;y)k!~tJ9)m)k{=X<*lF8Db zs$xnE==nlq`ZgrnRcDhkV<2eSaEY7_2q~xE(f@T@c{R8hl--HdYszunIkDS zncS|$9S#h-GF@tVfL)F_cld*Oxl{T(Kvrah-*?US^m-;X{vWRzR6!zw zP-%CmWgJSfi)QOt1_{4^Nvri}eK33p7nEATE5576h`v0{S9ym#bNQjn_c6D?BV@%_ z66YLpSiH>LiIPkN+hb9PT=)<#0N zKL)4ANHYHZGW$B?FuB@whp4S+*iQkonjE#qH6=>$Ab~ z{LvnY)mdg898pnAw5ty58F`vF8#c>}<2Y3;Kw);hk#c#6->8Tij=Z514K9p)2=JlC zjf)fXGYm7QYDbhsCZ0XNrS3Z%GTR^z+a7YH>p^Tskoba7 zU*=K<}0{rn9Uz| z_^&-)eA2hJ&h&!%*Qp5?5;fnv<}c{X-j*r4ZY{6I@->y7hu)o}W!#@P&6UO}HC%Jx#G4)Jm>snM&aQEpH*9UlOhuuJ?ymq4!NAea#IYqRqvk5yM{=1ckS?Q)4a zp|kvn5GQAY5$2i;DZV9e$UF_Vw{`BsZ}6noP@N3_YwUTgA=p&fN~Zo?dWwaTa;hnR zzc(GHkc+>gkMlbUe^woQmjCJksP=8gKLHfbKCC{cM4<4#sI@XW#^*)ixIXSG98rHS zk6-QQDsk!6MjzlhAP45<)3>ewyhS-iq%HHcNZzdbvjD1&?NYuCXoPt(_65v7`M;*% z)*cFn$eJ%iz6*F}_88(k1pSV}+b(_jfx+#`Z`W#NKPqU4R%s=}F{FPJQCQS@$;2oZ zH!lV+BqSYh$TSgXe$XKtcrUx{n43kU6$AURos?*k!0Lg2-)Qb^XHI65d;zg`kWx!5 z!sj#cUQ0BNf($ef>oIQEYQsNtabosY8O|HFqoc^q-B^$f7Js^!U z;%o>Ny1gidX>YKJFvd@=;Ws%Hz1Nps;OC1qO_;qi=BOJ@+_BEynZEl^Qo#N(zYW+nTtw)KEcZebMIW_R+nf@rA28=%VJ!|f)mJV4;@c|8`8W*q|6Lh%)I}V?g|f$#)>%zXF%Z%ig|U=e2a1!d8QZx4*i_qPfG1g zqq^h;@CV66M+blW9Z9!jXM1L@jBM^I@27RWW&N;6#GyJj@rB{(VuqgGV+&{?pos~& z;T(uf0Z@p`>@SuhvyxN*cn5faj2c+m#X>O*(amq)tlJIZe|1{xls+nS{zNiyw-K9K z4mYYwWfmhy6Sj+Eq(O2n_oz^zj&A^nkf30_&!tc_(?6U6&HK@1o3Xr(meQ-c${N^+ z7-`%F((|&9DqQ=j%4MWH&N{LNB zk=&3wXi1J>~B4*q{Q-n0gm&WfjTQi2pS}F*UDK{Vscl~YK*T)G{ulgMR-PK$wTIPjZ;JS#NZMxnM1Qzw= z3P1fKcecal8cl9oD5@3yY?mA*|5?>MbB3I-&nq59jwB&u%fO=SzbMu8}NJg|$Kw=`Lhnr9{9m_9*LIjmh*& zUFuA&2qpIh{7{c4^a1C^x=F?}l+AUTxpF@a@pI68U8I7#U{Jp3=G$k zJ0-{O>vtCUFP}s=#_VEIR!Sf!cX4vyMlfR^$$Lw-gzUBo?+kew1|WKcs`QGuMdzpGAl2`zj`U&RP!Kejy1<62 zJvxdD?d06QW`zSAZ*Q_vJZ~{D?d>lW+VFF9)p9ZeWNk;6ws~G1ckpOO)02EwBg~G= zBIgkneZ$>PVL<2k=dGHj3*rU0%~|9jIwOWFlWU)!V_fc z#Sd?w_0_jotUO3IbN-e#CdD})7Z)1*yS+a(luQ_DY5`ltYPmjq530uJ-TKLp!km)a zU20B;YH(n9HS7i+YI^;Cn_GB?iWapXJ@+?qvFhA`{Swu#o^`au={1>1z}DDM#!>Hw^wf0-$H*$iWRYKcE&QMHEa zk?^fCNH}rkIrK0XE9`~AdC16){HTNqnL@;OR8&;l0J{XvjCW%}KUOSd{$Pv=ALIsL zf-__qKFYrZe-C3*1Ahij_Uwp1p9IRhUKEy+l4@JjxVgo(T|KzoH!ujL|FIiv?rPdv zv?p%Pxv%*KlLFz=4HvWNuAZ9eP0f-d5whi>K#2`|3uUn)sl^7O^P>LuOL1M|SJXgc zIK-miEbpr{E;_}NyzDljMy3(&cWc#iAcoNAfNk`TfKF1#a(}2%0Z;OuwMj!wXi}oV zt(Ty&h8nDancyu8H4_ub+hJm$Ysc)xz{&rh>n)h#Y`87$CqR(k?(P!YU4k?kBuH>~ zcMtB?xOQ-N53UWtf&_PWcW9V?-gCaMW~S!+fv&D<+4o*+?Q19`Tom0A_5^ zdH+byoU2YRaP4BR_F*mV?rL;l))J9EPZo#|f~DN%v&^bdwaitg3<~qOke$a9C8%0F zx3U__TcTC-{hzhuvctC9rpqr0&BB(g3%)^sdRfk;%mLPv4dCMojP;9tP)y{r6NWulj-G2Ebtwd zetnx1xG-6&b1tk2sIyyY2or|PVY_fnp$C<2qKn=}3g3Y&Lj=E-^FMZf@Ka$Qh`M+( z*m}Wh%{KK6mtC3Y5@R>2J=OduB(y&w^#d*q3g^$1vf6lq=E)?U4zz&+@#pK`G6-X^ zF=LXVHebANlB}b8Hqzu*c&m*Y3)?qFCE=l=CXm*$&cyOhb$9|8WC+`LxN8YTI6M+p z3e&F^!}mppVY+w2GM-yk0atq$)iBRVg;t)vFMR-5aZWQ$$DPU zp`I*oov38nCPkSK3@c5K`!0iR=l@7#;6!ONZcxmAdXNSpC<|V}+0|k-O`z&{0$sv$ z1xF5DSM?Hc(D6;Ux$18D(UJo(wJr8PV9?6rK~4i@48do?l^mLgD*uHhq-i zK>%ev?ZIe0V#k-6#g+x>Irx0`ljiJEPY!V4ac(VObyz>?jC@x!IcN{f&r-@Ryw|0b z4=ydZ@ddCIMh~NMs!AvT^m#bR&(Lrd$&KZR#JAX)_fcpoSClKCP%qk9^l0#Sg&$o> zC3m*EF;*%%6Q~}~>x4cd@^jOiMO*`p7zC} zoW~S!R|n}M3FuWRuOdkg@peU1!hnkd46_^jB301{WRsoIQl5PeH^q1wP*tZ z>vx5@)Ls$vG8Gb=tLE1ff-Cd5&V>^tHR023e-#jFAC`LEpaX@x728<>7Jv_!^xZ4$ z2ZUb&;>~(4b+0V#7(K`PP9JA`A=mHWr+kkWt&Je^n*mYke4GrCOM zDp8e>#!##$ic3XB^#=1>_O5@d4PWLW)DCC_`@Q=Dp`!?er7#h-L?umtY;3Hzp8#to zsmnq;TyK^Qd)KptzjEw_0d4)0-i8j4wU(^{H!0B+eo^c{|G1l4(LX4&Hua9~E@pVl zTMH(3sp>9=fqb8GcBYtNykWmLC{tR8N|Ht&cOjJs@bRL3(C6${Sq+dr~pA_$`7~4CfyD5eeQ- z35MNkB#bR9zf|26LTq4_DBs#is01mBrkllgn2r<2swz#F|D>7;g?J!L1;DG2&Oc3G z{ZiAL_s~#UJIl6bvQfF%FDn(bP6)-go8matdWXKw+h0d7Jw1;VunD_ITyg-zoO*T> z*yEXc`pa3J{@om_g1zU-blR~^Ckx}RaY2Y8Ob~4tGLM8&{+jm$xbad^k%`HVGVA0D zj&us9Dg1vMNdL!ta>BsagcT7*xy-`g^q~nT8`ueF1gYG(eSUWAAriA7TaK-GYjRtH z^sfZnT?2AU-x)`5x}&T`V!pSe`lE|D)@|)%JwL3mAQ8{Qf%hMz;nT7&hFqcs9XIGu z&)WnS@vFBnwBtjf$qBWY07itaUAt(+_T!}#P)-3g4Qvc?0^UUS*!IT_glu?JLRRKL z!P{hc?w?82%FvkB!IGvqB1?{&=zGV~3{i4KyFDARYpUOs`L5~l!~)$|qB;U`IxeQR zl_%M$iyG(N%vfy-TMyIJ`B4f_gL;7+O&*7KYOP7n&^gj&Euv!2-K$gxXd)Iup-# zM{&(VMW?HJPxl=c6JIVq(BGyuxhbN6t88mbjq~4RNO_8g&dfYg3dP&D1}h{xGeHX! zQ09 ziVic@KS04m41-A^ibJT4m8?n~WUe|6hlkK5l^is571xvD3;;?3BIvdqf82aC$RD&{ zqet4P#v^a2|LQ_cPEGrn{R0{J%kLd^nt*^qfi;G2*XaIxujw1^Pc3)+fR`I)tX6N& zFU$hT4j6%-N~n7Sk4gW$cqi-{3ZX1%#ixeWrpaAD)=CXOos+0wpPTEa965k&l%hUq}!toza1@YXzW?x1ctoB#z~ zrs0_FFibKhrK(h?olcnBhoN&riM%I~7G^PvDefakETZFN7gw!?wC$7^&0jP{T9rA| z&iU>x#nv1SY24#$Or3PD7F8mIVUf{H8{gU5Opy>-hUiw&(pyu9A;ejxIk~pO)#+U^ zxud6BC)nMqc8HM*2hF^i=v5ObsVXU=hR6$hE_%T#KB7)lH1mBTq&fE4EegCnFA6k& zLzah8SVl*BsYZfTn;uE0IO}Ncg|&c_uN_NoZ~bqINaUIiZ#|D5On2qB)0 z6R%J0z=va8wN6@(4rN~4#7^hDN&hWAwFcKX8tTbGvID?Ye=E)VY)@F*Lor|Ct(boZ zuVUc9!^d<=O}W(ch^d|F5B`}PEK0hYF+;uQcGFs8Mw;27$Dt1$hLO#412i>BGO z_uSs3l_u;xZ!kM`%6QPds)1+kJW0KW_Q{PVsOoA0b)`r@go;EE3I!8F-3!@!RmRZq zs@gy*7_Tn<}0PhvOgl~qk))lYnm(h({p)Uab=wY+GmYB0z>9Z4G4%0?W7+RwoR$YSX! z(66q2ovKfL&h%%kNtkvE@fBeJ#Q?%e?pr(LCdSWYECO{8V!pSt*J63{UjuF7$3F-5 zH^N5{Kc@h&@M90TEJfX=xp}1a_fj8^K~Ok=*-q4J8)s|w%NPlW|JG5K zC8%JJ&i2=!jWvBqc8g$s6w?SG_G)!%R~k5+f0FNG#aY17VgGB#Ttx3sOBzy1`mFZe zX>F+wsnm}*&m||7&E6Wb`gB~c?EK>K9VSqqjS6XDtD$AO4t@YAVf*z{ov-vCQn*wI ziIhL7tXg<*Vat-NDoAhsS3JGdT&dFMza`JkU{s#MG2pXc-kY^LluacX{cK)NeqSl- zK8L2zj45ic^T&e}tOjW`)0->KTj4vq9^kbwDkp>)yRWRXSO?WTJ9G?J&2{eYV07dD zzt^ie#8*K~cE_T=3SY=ir`yPUFO$t=Mv(s=V;v8!qj|{c&3L7n8ag5Q<#@sTt|jeV zB_l^B!)ZW{*(xOQrl`10n@Ha`=<)h;M^_vwH0qvnC|s?yY6kaSBXZV}m<|`eU(f!NwYCeCY)bHH06+M> zbm^GD6iiDatgk4XR-261_t~{XN}`Y1oO|kAPqV@wxvO6}Qf34FGgyShA2r>cGkARC zPk9`39!BXw0d(X6B)S z*Hw3yS7pi{vFW~sa9eM`Y6q@>F0N187(~{;I7FMgK!)@XH*EPw->{UG6Zj|f{f{|&7+8%2UVZ!Y$I{5XgSBx*>C8baRU zVdV(Q#Q1{8N*6SgS@bQ>Udjl`Or&5EB_|yj`Dw+fERi4?&IE;CFwD{@e?Lka zRu;d2J&!goY>v;sR{rUp3UL;6hs zF9Tjz=3!)f5_|HRE_prhONKKOWxLL^G{)a|N2l6Vg2iW7M>7(iHxaN}MPQe-hBKV4 zTRUmG*YasPfq1Ai4^bQW0l5%&PbvSot3?BnY z!t{}7#(`LXfJ0bg8RA+R0=AZ(WRCqm7}~#rLz9*{|K?=J+(et*xt{FxW{oHQwF~&J zZVl0;ubi3`==cr2^0v>SS`#+_*!(zR>+NALlnaoY2j&>cgTSE#Zl4o-X9(f&42T=V zjdTJcx$5T5G-ZFS#a{Gch+-}_vWJjRyJi&h(FT;y7RS@fE3?}p1VEDpW+M5gx+y`< z^&7Am5`Q0)S1ABKZ?IEU1mu^7PQ;vbyZo-J+gLlhhhmyb3^s+fbb=W7G6+1Rx#I%G^m&Is@c3WK|4fK`xe%?G-i zCudBDG3rZy1ilR4sdWai8I|SHxRKH^9t^Nf3aRPwbXYG0QaPipWQw~OzI3IWu0@_Q zgEAokFPXDLJ)qqXwJ6&;vITO{!2bAnSN-`OpNs~LLJQksIJ_PlM@jg!^jzDo+_m9} zurQbpPe8*oxyeC=g7O6~awI(L$&I+R4+mlxOsoN2_2b_iOCE=IeZA84ym6Pb+K}!K zz<`4Y-EaJ?WG8Q*M;J-vl>6FVdaBr_{I!J4R)3;-U*BJNz^{lJB+*I#K@~`?$A3_y zmugjInj}8VX{MCE-!~!;J*O8d9*tn-RALO0HWQq`>eqU#YST#R?N6h(T!>RNl7PpP zZ$e>_p*&UTn!_TT;n0#HPi3a=*q4Jr6B{0xf*p~(0XZIr#?{6A_ehEoSAtCHst;yF zw*X^$`y;Zowg<8u^vZ&Fu~~)qdfIrzbF~mYtMa%XGw9Ix3A-=KFUvmBi zYEib5-d7$b1fBC9&+zV8l zQ4WP;SFctb@s@ym`}oqY3GVvyyay}!vnu{~Q^2v;GVctEZR}x_mcHPAgw(H&XPT;EJzao3(I}COF1IxG0_z{ATg}^uJY6-}- z6qk>ZaGC7ZXqalp$qE4I^~fBr1=^03^*ey&hegl}iB+UrIEyI}S?fo-BMcJ@@T&8V zlb5mIKQqpXC75SSj}jrnjD5w>zI>&1AGTCGK^*Vx$9+14wC;tzLB@H#U$07clfYLY z&&E{HFD4R(HoG+={L_R^q50~~lwj6#3cH=2S0k%Xv0Bxrax57e6991^Gd`~w?9r+9bb5}jl zHv*U%2$E|fKx8Xdx8s3%iO7=!a9F3~j-5{}tJkGMv2n+*sw7rB9O%wYD|@^GDC9lQ|04Yc@aO)v0ed4gCi6^C5{qYFVVbP9lvg+8mIUGddbwq!`cQnzAqw z(BqBE;WhhNwAndu(Q^a!YdOs@I3XFJRRyzS?mSPlwI@oVL~qX=+99xKXtW`gMRm&V zyN~C4*2@BNQIW2z_B~)m$n}cRx7x_A{Q<;AyQV9NoJ?qt$4FaEBtM;KO0#uh4t(9# z(m+ZwNfdN(6heNk>lBlnsqyD1djHDGKpDExv%PSZGG~LK9qrqi{wkKsNQ>l*6_IXA zBXU!&s;=J&(d?ZcV>(n2>G|1ox_t~P@;LY&2^YLHVN36TI6BjZ!eT#V z-B%6GN&1Q#E#bInRqAKCb>%nG6ba4hx_Iu6R+KKtzpXEF+WoyyRrzJG()T#I4A(zE zNms`$+}-W=tD;MQj(;>F*)wP6$>PGVgHP@wJG-ZVgm78&T_frB7&xCM=%*yA21?N0 zhXW#+cjOE0XcU&>jWzWwnlTPfkL1UcUfyLO^O!gbBjaXPD%*szJ=NKyqxrlTGNHDn zMq*G{+V^-H)@qq%@#-(vT%XLZ*2aE&Iwkr5<&2Es@$8t`5Lu9N5rWLF9mn7LyO`y` z-WO}E(qgG1hMFFC+s1r%FpF^^Ye1?|--i~aC8e%c^C-ud)37#K){N)KL7sDpsIE-^ zJCHY+Zg>DK39jF&2DCeXfrCUbqHlGK=!flg=#GQxN9|Rqz_VK`E=_ z;?krbWJYv_n^!|gY-LGBe}1i{-fEf0;mj1E+B2zk#JO@5bFZ!SLQ*Q)q?Go0OsV|*pMR_p`o;gEz4V_n^`T2cTy;)LU;{N0h$ZbCi z)$OC7wIm~-OAYUjw5w-pI+W6JjpEfe<_ZIw&&bk4J@om~=C=5sjYoL{_+?gfv_$M@ z%{~22vr%9aIOVUhdL=DL0>wcqe!>&JbP>m)drP0RrT#Ny{~u1$9OgR;&Fq2k~MN) zdLe>Rh&0MfXj6I{X!cQ9O3}z@9^Uqpv6F8O(Zr^<%SlYRX?G-YXY&1h0ZM)7f3yvH zj0<Ac7N=1BwH~7c2#Gh=emzRe4Y!C<8D(bVMP5MDbc@^9gWyvNXTsj`b%-v zOYC&{dr_M{RT{9Rnle2xo{P=T`qN`U4D!C9nvi`xB#1VR?&9&^g<(2(4Z0EC# zmie5VLHiZ@g0bw7E?*MvVJ9*xVED~FX^ng<8N(juyAQ%xRyrH zy{)jxekCg%ceKylbn@Zmca>-9zp@%4rZ5A#5$Bs;LIVJ0*q!o&nS`LB1|tk|VAOSp z)wTU#)NY6}8Aa4+odR%-1xx$URj-_ehGs|gZbuTY5SdB z$VHj76b~9Q8AD-esfr9|E6u6Oq${RXD);9r^miwJC0<3J@N@!QTyK7dI=ekM%#bXF zc(FCvgFSRw{LBe+qlqf89l2NNV3Av??`I*I_1KXGOHKak6zqP7;$}w9B{1W0NxhtI z6o@Q~t=>wadPpo`)IRckxFO^1IdaA8kdi_B#Vu5;I^fHkHlwvBKH?*d`HUMN;}=cA zSwGYz>I;KaB)J+3OfyN;VgEAY;1BQ5+W?8&8!B829do;;FR{ z{W4OwLrU#JfEx}Eo*;cQIo@;`5V9lil(`WDX}D?znIDiG_{c!*AJ;lZagTrwp^Tug zC3(RRKdkieMlsH^s;RVZQ`H~6sqQa|ppenM<#>ypvE>w4m@$=M75DeYwgidS)Nu@r zhcdyL{Zl-G$SdwXwyO`uf9rq4_t5Yur#_nLy*qmXdm6>%Kh>+i3IY8*#;Zt@cs2{< z!=RE_8=^}e2zp~6ZInO#EOG)!xBcNtf^!-8uqx8va9vXNmW65^jKZS4p9`^VG~2_j zEIe*(oLKr?{E_qi@-@3d#4zCXCHfP1t_cQ-C2HWD{ee6zW+Ps1JCY~-QMvSo*){hh zdek->EAZ9xok6;?JKo)^-3O^I+pmwS4K$cikCkY${+5hWU6Zv|lw6xyr0zJ3*E_3X z78d0=3r^H=0f|V-a|SSCOI>H8%b83yPM;?i6q5ti5j@kT%SXcp1A3BoF>jBOwy?bqd!Nilh&t+vb)bqOP+yK+M9Kc7`5 zYG7d$x;C{ngW>QP^sZ%0pKO%&uGB(EiEu_eMxEkNSV3|C0)Mbf@lx zPPvYSK|iOwjRRldsm_AxJ*qnPt{vRR%itk|2o%{c`>y)K2@{4Y(E8+{TmY8kJTb*!-}729DjK5Xf_X+e*)X)j(zuJ zU9@wyJK{Y1WonvBUc;>L$=y2Q*KO@pL!8&wIrNiXXx}XX#5O7%#=eBA#hj!;@TlQ2 zRkMU4M*qAz39mFIxZ|P*+n+n1b2Jq*U&KqF9isJ$&M%#>GaN6VraW&G+^aXm6~`No zI{zvx4?OdHG0Xjhb2s#B+0stXz|;)Xp%1Q)>j&EZGH%Y@nZpD9vOcv@00(w z*3lud=!w*F)nyy z#M>$=vO*&a39HNi1^m#%P&S-q2YN#Ew}scAU@#x5W4qq={TY%Lv!{S93Rhihu#h4N zba|&v>ILTI(Vb|12I~&xg01oO1vR_#L6nRy|^S!ZZQYUuZx_A&kBa>v9wdw?RpM_E-{Y4!;zJe~e7e@L zK(t*sjZn#u5~@b!HJ;$t#X zIWSfENDoTgE7P{Tc8U~0dU_u_#xkHU%)lh1D<+v9vKRyJI07=0-sZ&XMo zX#$c_Lv%PQm_y+6XaGpi_|3!j)X83$gFQ^8*tK4`yCbe1MkyoXRkWx4%ytW)V%8@Z zs~ZcY2_^wT?ME&nJ0K891ufMacE@%EA}rAe5f9EWMN-yM*hZi)820qQ?WXQg)D8xK z4n3BL4$d7$IClo@>Q;j#Ga(Zso}TS@&}LNR+UlGiE#5b54K_-L5JzuV@3_PD;zn+V zWrFNk%Z8(>SL@W>1N;=eB1K<$mxi2J6rokhL-LL+I|;lDT+D{vy1>oR#lQ?}gpiX=E<_#0PY$HC z0cH>gx>2}dp{Tn~ic7=U$-Mr~Gx&6%S zGV3LQdG7^PqHZpRZ8Gx5Mfp=~jPG7r+v)FWnzfyH7?4k_Leig-wuT~3)K~lOfWi)0 zj}6zqiB-$*jbyNM5_ZIm%H`qlfLbU>;cN)KF&|L8&HJ9^hcGK$Fp>B?bFAl3gNlg= zO-=3yzo8#!0&%mbPvGh4Otlh0VvAI|J&Tm#y)Y)h=qQ7vbg*L<)_*$k+(=f|6Agbd z`KFsuxQ@w03}XIOwW8;$bNhf4{$jXavTB2^jg_ccawctGB!O;*((73PVZI+5<_ky* zh6rkXo(ptOi|;P1oU;Kbmzh18R?=X@8#$vrV_|4Za@AQW+E3XtDn;m{8pNYm9Dvw^L}H{E*Z_2Mhi|S zJ=8}=Vqv6y16^Hgbc(ys85-nY%_$hBJfhKO>UVoh*p2$bvTgB?a5ky4jxa0lr@oqi z^uorO4K;!~`|D~CvuV+D>lbnqJj{m2>Q$Ozt?fm-Y$9&0htj8Ggx~#1+Z}D7(i|Q2 zhvJ`~bKYf@Y?y8Wc`p`OO(l_7PBZGEhNS@#?FvIs7(^va)~N4Ujn%u_2M%vp+xZ30 zI%V>yLGge^|)^7zX#km>fTWJ&Np8r?tJ|`$F9j!wdvt#aigtP+`Lx>JzB?6 z?*Z~hI#Vcox2r&0NFe}epjkZBj;1c1uA8AWfyDS;=Z4~w(1j$1(j);ym$8r7zLFVwaS>ze z`AE3l<9(&BIC+7ckt23oRe`BQRb7hj5p_Y>+p6)Jq0tHVCEK+kCvI;;MU)O-->ZAc zqPFKMZPjN5q%fh?cs~O-==*DU%ycTE^^q-Yc1pNI?PVZxt8_FJAH;=i-00e{cU`|= z)ZlnW_l7Fqj^X8sbSjxTa0f#sp%U2*@+C+ zt(7Np1e5y4cD_$$t5tf~H$pyr`eb(cttY*F~h$g1KKfAOAt);@NPw z*rhO_BV(@Bm2Wb6?*e^`V`U1w3+QJHzPNy5;NZv~U zYSgk8RR0tRDx%&Tyt#P&7()YFRATinjO@ts^{TU)Cj^g82ha6Bos43g+j@26R94t? z8tNWqUUvLhGMFamc=p*M`h)mF8?vvzmLo9U-Jfm}{s~D6yiGLpFn6%K`J*hFR!hBHU-*nu^EUQWyc}%_e41q9cOG+ha@JpVjoRLnbzp!BW zGKMxhC{zShY-H#4@~J6vZ@nVt1BV^)cgae~Bx5-pZ8*Q&WFhKwpqB zGzg**yRRQ)dlAr^Xf%&-3bCtxZAH5xvw=}Cn#iK|mC-e$*t$zwv7U|49aqepAL;Ek zx4@@lESmjBk-Hg$pOAXi_%Kq^%1gZh*xQ2Ucy;s`1hO0c%{ekT4)O$>W%!Kn_V0jp z)y^HqPaC$UzokwNZ*vmY``n)C7kfl-GX|kATf%2aQPR}idi}GYO`^W~j=!qP3yZvC zqM3CbcueIkSd_g}3wMy4no!I8_$4}_yN;KY%pbv)mmj%5{uQvz1d8igiK%d?-EoVXPD*tV- ztR#$c=a;>3zDx72B8J?)gL1r0jaCfI6C7L`++gp?(cXv!r@On&9LKaE^udN_guRZ( z#zYzpZ}8L5(TUn_zt#XEOIO3*hUJ-bt6|=22`gt^;vY>W=(Ek$V_uYd*Y4d2TpGMJ zZ3ACKPuZ9BIhvlTjvM?agm&PcwQE%=Z&OvDTZxv1|B^&MVX(7l4n|F%;N#w}>9FjN$Z=4x7!yzr;JG5k^#ItGbl)#Z9DDfh4}4Wmn&=GQEnf>v1X7KfpVsn_H5 z-QPQuR+Vg=XG{GTcj1>s8Rr+vp63NYg*z30R@j1 z1;|gEPzh#sJxtWZoz*eHc-pZ0eu%SD#^hi(sIKTW0rNNJTwZv_;hoMd5kcnT0;6*W{f0-*MRN zd~i32bAZ|y0S?8l`uRWRK}fLRaxTE@J)6e2k;YyHUtwUz7V>Jel!kOuDHMo!)4CGk zu>+|B>IM=FkccICy)neB_QRAS2fhT2+d8Iqekjcv#ST#9tO$IshN9)@3RVi{&&)SA zB&fE&*a`;$GC!(~RF2YGU{np%b|g4*r1OmiJUjc z&_;+0DHguht?%s*Y@V5|@jdJT!LN{@K6ibjV zoK7Flr?Q0i`AtUU8{2R8ZZn_y zitg^%k-mm{M?VbGCyap#KSnmF8wJ@KpSB#inR-J=Cd9tHzlT7}woTcSeCkchq62ex zwv|cnov-`(N$}re{q+94(&BHmd7T<3(}wlR3b6)zT%}o?@*Q7!h{m_dI&}&p#J=DE z6W{ti9MH+p0@Y^MI=4h0=Lqdj7910?mC44>Gj`YByI4y%KR>0Qj<{TAyRtIynW{nS zH}|R+4AbICg)$(HsOztRzc-Ef_ncwVqqloo?R(_>3OB{C=aS(Kb3BcPH@{AL%bsyc zX>j`y0**Y87a^8Uk3=00o5DyG%%afVa!P|5;#R#TNInjxZX+T;A~crJtU%vbn~lPP zj4vHZhxzb1*D0sjZi%FoW>SF4^!t{53UMB=e5)nH7II+`8ejLWGBJ!U8z z=crK5=CP-O;?D-(NYJmB(SZmBk-G37BkAm7QhQx~|G>_%#fd-2Z0w1WHi4lnmg`=#nfF5mmh2vYZ@>5 zdsP8!}cv@;^R=r-N9Q4_> zJK-#DDXMMCe4bc8&=rP0@$nt9`h+>EkYr+{t8V5baBpRi-&e_y)MZYF$i4-K=g=q$ ze&94ye*WHJ3|qsN{hLdtB=-tUbkA%M4AS31?04TUI=ZL_$x!JM7R$d#x|jMU6bsn2zt`+6RdE(eJC6IG*^aLX}el7^6QaU3Ou z=-iDwT)l!OIg-sm%mOb!e?ixI7`&T0E)4K~gpJbe5ZS-_riwBgbEEV6dB_`qBK1&;B^+yUdG5N6tg^tuDUxBFcb;olhAPKLoZ z6VYIFXoIw}9`d<1mGlzkB<7)VMK%L?bxjG&*7X;T#nl;OqB%MQ4$^RtZ!t1Fd*3<# zPu&;J1>0dMZn!t?oa^EM}ep#YwQdmm|xG)XeW)B{PKHieJgzq0z+fbq5n>y<3N3 zuDZnCB$vrTXdZ@Tx*dTAeMvOB^;P?fA#Saae8@SCfwrA6Z^_&UNj5Gq#TCT<(qnd! zx(dKo80|KcG>Nxe{-y@*q;np%-hX7yxN5=~4-oxwV8lXmhY)1`nCrBcysdOY`>@A> zx%RAfEH{&=OIwd`&=PE!BK)56+VI82upJA(r!&&jrr>J4&}H|@^+67Xz?884%7vpL zl4aFoT~`0I=Y>JHy0Ue|U2n7Rz`EDdgo2W}P(%F}An#qw?u3FTpfsG{!MU?~DVc%( zy|umlE~e43jjw8>=ATB1mceRw<%K)VAdf|v zE&k}`eEs=vvfxIy0B-kJmrU}wsQdo2n}QM_7REVfVn!jbDZjwkRR>(5AFm#0qXItW zkISWnG-?P{RKDpjp`Gr?p4HU^sPYsD>V17zRtfFVsF5T1C--ZAoNWjEi2>o?Z{#T9 z5R|-UJ4<4a#n-vC8jO{t+PA-C>5S*8vvC9tF~1!ATa}gz*;>lcHA09JJlTlI@8<9n z^yxK}^cPnA!BV6xH#_&zx_0WIPE+@lB37|qtSrq+XR08z0XV!1`WdHwWUb*7zHuV% zQ}X{Qp-DoCcngN^w-lGpaokV?2t_4Ra6+Bt(LXO4exDp3N~$q=0)rS39NuCwaqP&J zPdDhJ#6G7ErYa0YjQWMG#V7TjgXNu*_y6z`srk;#0r({e#R5x#ty^cZ8O= z?@xidv^Uu6M@;`83m`1hV9=0d2wDNuH{Dg#=B>aYl)R(X{U~SCrS?SbLJEUSKmDVZ z)AZO_!pM6!Kk)bB7#p%llLN#jQ^2)_<;}UA#jsoQc%e37^zdx&)pcsvOe#W8VsEM> zfKp4(-M$^$JOo}pRkQj#5hq-BTi9c#+!(Y`Z%PqpX2`<1-DEt|>PSJx6C4D!6Vs;) z*_ROKJx>=I9U&LFUtOJ^FG@i}U$hPoX8uerrj__TvaUa`gBi5Ktkm+-8ArZP*Aivw z%U`*F=r^>#3c1m-1flye^OeUsuRk5E?5eb`hi0jC=icPz_^(Uvg&7`s40rsqOK^^` zg=O0*;!8pgQhMq&!zhT89{JViuqJr3)1EmOcLz4M^~1oOck9_%e`pPSRmhkg_)PL} z*+Z7d!Oxnrc!>wTBhJ}@Aw*6Kvikc2EFE$0vhHoEu(7^~4$F*r*7mhSc-;-TS~p?` z6}v6-b0i$=f!7Je0m!w51Ra?2{O)(0K9Zx>z7u!SWc5a(=mc&bqoo}hnrYBK$l$t$ zx|=d30oVE5R)2c6M<*wf@FhI5`Q8zh+MKZ?g`8(TXy-tCu=V`+aDh4F;61NKXHDMw zjvF(=Not2ELWD)`15znG*Tl!u8z>VX(@7HLEPc5vMPazO&l7LbQo%`77n2{9dFFvO zVluwEX*F|>t0g;}?m>=piayNn26q;oOFt!q;PG<%NgMY`7{d`ML5dkKhydd&4Dthk z1z@R=P#8vtnf|=Aq)5)@d&Sa0ru`uLeBXyeExh0+9gV>ap0RYC*u5e@ED@M=1S!tN zZr5~5LMK0;?^#6)%ISj5HVSGD$$LNOXY@Nfx7LkxBCjMUT4}d44lwbVgZ6flmD!(f z#a!=OF#(OR2xy6B&>^zS<)orU2Hhwo9rZih(UxzLg0>Q%$1hl>pQKDaI|dON1Aib( zPqhnM^yG;m6L16{nl$9WO{(Aayo;w%X2X3bK>|A+DWNODFE3Q-BdEzse4)?r+CYC0 z1R&AeJWhD~&h8r~67K!jrKm)jC^0sqploul)NI3>aUj_b#2-Z;S;S&a3V9hC?Uh(C zl(GN_;hG0HBTTtkI3@-Y%?+%is#q}&nneL~XggyFNB`}#e^%be4y*I3zuRSprE zY1MO0G{>u+{NsJ#@Y(6q<9dS;()NT?rEE2yjIjHOpkuJdJbBAkfPxY(&}(VezmDx%~=+8&|^5Z_c9;0{(ZAEgw&1oeoC9O4&_5o*b4CF7Jt@a$S;5( zdi=BS!Lc?xfEc6<5iGfZy<1b8DM`YCYORQBQ9TmXY8?Vkz}s`ZL{;(cRfnA+M%T3@ zRMG?NjG!P1zmpCuniq{T{BgqFX=DV zU13FY9tldx2@P%Z@3}2(ofvr;WlC^rEdR(Gg+V9~I22Iuckay<`m5@E)tc!2*n1RL zX-Tu>&tdURFjQeP;db#i=KafDG3_mgKlY**5IcRs1%~<&?pdz?@v`pomKA<~7PqKi z4uc3~{$it6z_Pe5{xEriAWh97+4)tFq2G=OddL_#dPZT5pt+!f@C)o&W1`p)V48fI z)kt6Bbxf|SW#dk>B=uJ{s4r!hapq^bs{!kxA&c+62}m>dpEupo^TcgoWwB`1@h>yj znQ{ztW{c=F#vHpbie{KsY8gSrn!Y6Xk*-6g5ox_MC*-eFUMV`(@p zE|dFhs>aox*d_`NN(UJ4ucAs!PpPu~!xNgHA_D-fGAwnj1}&(|&xhMR9UV1u*mGHa znRxp=(Hs1dB7LC|-HWyGY6a-HR$6rsU}I)j|E2iq%S*A@JH086srNyjn^xnx$4~E7 zrz05hJt|@?rP7J)E;CzzF=!1alKp2QDF~vaz>T@`Lsor15O=ADa9oT+xWs_hV0-zF zuapC*eJ!EP2)`Bb;Bb|j=zsrsL(AHgbfwndnYisTAvl7A>LWSo`F&ro6CUO6f51#5Gb z?O)Fr$^K^VI3N?4(@P2qCcd4_n){MwUrQFXpUmtjXJ}y*q>&S3UOAl&rL^LQLZc#? zpH(0h2}>7wIZ-Gqv$;1Ngg?Zf4>1TZ3MEU!>ETcyQTlhP#@Y=!CEG1O^j8;Ti7#)A z-_p+HfVe_fd+89Q8U8NqUp$N{V?LIEhvCOJ*&IqoR^{|;F}p*S#h(9)`D(@g_%};^ z=ntP(iP~WBzOFyL?}DlQ_|c6;^wnhZ%_+W1l)_xdv22z6zFgG(>7OKgGkf&_7;v4k zzkzX+8L=3N0%`m#Z`zzWK$X~TmSC~e*}7`?Q`<_pit0;6sc8AhDu4KLv8elE?Jv7R zk+>iz+|=Hw>kwqWT>5OqSzn>#sYjxqs>{MyQCU1obgzXP#)E+045AGws8gmt7j0<- z*&ipm2Ou`UM^#vxc0g||_xJ-e=Frl=f!te8v|COHmW}oK5GyP)&yEf6{^mXZ@nEeK ziC4`&EiEHEIX!4twot4(X}GT!$q6kGZ7O1QpX*7p`lLhO(gEoXMPb>u{&hg8-5X2& z+W@4ER?63crT0H;_&A7j8uEM7)Dc;KGq0bxRkSL}^RP3bBqqSVHm!og*UE%+nObYH z^h{nw{iSR;qQ=I##oiSmu!zjIoplQncCU4?M-(!E%av59S26{!MMQqq8s*7X6KszIaK%cK#7hZoyH1;8@z{>j+}UIQc9pv_O`<_8AmRnrSk2vmi+hXimzS0+t)L%R+Bt*~lgbL5_3af~Du)iS zfI*6!#Hw~8n#kx8=1)e#+Gt?1HT^7ZhuzoSQWueXV#B3zGq z^}jfK>#!)_Zf#gXBoq`-I;BC7hM_^adqBED8tD=#0SQ3~>1OEeMj4Tkj-e3-hK`{J zzT5rmXYcp@_RsG00H>n_uR9zTaaXlvdyb|J7+A95&;@CWS^01MX&uehOj3wlf#%Gpa$Mc&70AB7_C zD>$U__^WLwtTL)1lx~e}DYS6bvG;9S!V|HzWYHejm@6wt=yZ;Jl#}{V^^s zTbNFSD#r&xgDrBU`Q2wT-_3CRMeneVpg7`zyLFmwoTMUPT=fI8RO`M}<(cJ-@iA%d zcDZUk!ozH@z&Rh?4YSYo6&>7y2pDxA#d#{fI4$eo z?XDoqPW}2t+K$Y5MRYz=u8(e?l0x*BWC1_XBkUuav&##07p96)M|1qA;_8=|Nfosl zLf10Yeb>qVpjD26b+71q__ z4Cpsd-)#)CTKv$bYI1s_evdeVrj~j?lr_;hn}p#l83%;qc4n6Dc4Pl8nrkp8*eWjw zn``QW*-UIRSB1C&2N6T1fxgEsC=g9Xh#PUDeiyQrh)1t5u#endeNd5wiLShcZMC2m z-#TJ6?MLglb}%^lrPn%JsYgGaTIU$Ik8Fuw-=xD%&_OgshEH5?=#j)cx^a-$ z9<`&B0$GV1F`<=-s7q5lM%woe^S1Vl5<~a*VRLtbA()qa{*SEpi@JqJAC}H%v+D0A z1UX5Xg;Z%0eU$@%<`cbjtA4-7V3Sqf4joQ(AjJZ4iORkyio4m_86WbP1Ted+HKQnG z^KYcw@f7*Oa+{R~RP=J@N8mW*$;jo?a*68`Nq0b=&e+#R&54y|?cRS?4U_T@+G}@G z=y(&XaX60VCWdaFd^7?_YXjDeCvrMFtBlu|-=(?8OJj=6+F+b8`}8YBs1x!0czm3u z*q*HjtiC{eZ$&xRzBssXTd1*2RVUQaUBB^uM%=iD$Zt0cR!3^2(c<(sw-8a_Lh-Tb!^-Mn)z6LjXJUfgjDyh?@?c&5OgT40eo|*@cu6IsZkM zc_+K_K`N)HlLoLr`X;)adOSCiW#QJ`nUL4)rad4G=NXW&$Ih}?;l{HSKD5URuJ2>E zKRQpm?Mh)-1&mjE^AAhb8Q>p13J;sb(b_1TANEz6CMI)znuO4F2W>EMw1m3yRDYEF z5u})P`Q7|ei0t~CsoL-bzgHRD#t2`a?&ZV- z0|JvQJ`-~DUgmHE^2)YbrpvW5`!77U*c|#MAuFVG>%R&1OKA5c&F6<{_*~DsgP%_^ zRtKEkiu@25n-L;M0)y^Xd^ll*S^+mbBI8}A$X)UPQ}oV9WszJMJCik`z!n*X`x*{v zC>?s8<%5fV|G_~*cUg^wz!JwUfgrS9;w8~2dlFRN;W|AEGc~8ib4Or%4jxuA*7VKI zt&Exk6r$<<@^iRsIFIGCxELH!P8->VjeRS<&#zrNdxV!JE7`g^m$MGOA5C`}i}(UM zJj%*eZL7CkBvwVroD?xQeKAw7hpgF_yJHNdO-7& z_byPp2xma^D11>`MJ|imgK0!0iQRLF+e_-FNZ@a56%`js_ZyFE5_-Jhk8ByE(rf(i zfnP|t)xkEeZ&rp51l9A-?hcIk4yc|tn|a|VygT9CtRzd+_aIhDz2pFutI@&1lturu zANW>kto^q}Pa%=zM5i+aiqAoAm7f+0-D-302vwLyx`iz&3oVz&J_U6`8S8ky@ zn_5;krH<{!ZEq8&h43F{h3pY;Us&#r1Tw|Rzf%iL^!E`p6mG_TDB($~P&y*c?|r+L z3bf4D0Qp2vVo6fMbABlGT*RgTlxxbh+7biHhDQRMWdda3Yz@;#Zi&46hDXImsL!dp z?QSI4jDrbJtgO>^X};9#xahpb4Th;lU%gF8yxO**5~dcG9S-{G$b_RTptv^qoiM(3 z{Lko|W#l7lA==X!y=GbD%ln znq-7xM-aMkGW*9SR|ag3kQMOO6)z|J**!R!kk#Th^22Pu4>%k~klzuC<9kJFi3?%S z`#4SsomPQ<|YC=cq*h+&Uht+ z&1bw1b+q}hQ0qm=6Z#@Hz@^W#yfmR(tJu=XZD!1@cBaVvwf~_UaX1l z1Mk!F?g{?>l8CMr3~FcC{>IL*T@M?s(FGa}U+w*PVM#(&Elxiyn9y6)uo!yzVOHun z&bL=bGbaR5baQw8CopV_T`U}qO;|%sPheK#^X%X)%v0D9RpN<`RhzXDBZKns3I${C zjPIIqPh-S;52IX;p_II**@`_WwC{i0d?xd&CMUc$W@3H5AKiX?OMhg0keG-e^1X{D zEp>WCdMNw3*NCau1y7!GWqZH?XI(7ifh3>fwa5%b=v(`D;DuHR6F>2&bqKnm>gnJk z4E!IyP#fjQh*VQVGq&)pz`kOFcS_-4-SYIOUG%Hc&VY{(IZ$aK_pg^r6uAk((}nba ze>!v9H@fOWkv!9^4CCbPdGNGY!=R=wxF5J^E#l%_$0k?=|hQty^V5PllAA#~XQAo2_D`)m$XJ z3t>;bJfwpV@_>(RJ_mBlk&u)m)k~Yxgrgkfp&HqF>vJP`6>XV;l*Q6i^PArlU~_Vs zcjelVHLjvgwN?_!K`e-P&qg-`Xh~e-&ZB!N+bOqGRj*UlS@*${!M<0k>z)RI4jB%S zsOUPkXWQ}kag$JiL{?G;B%dAmW-V5!+5%clr8hb`>DTw&?jPrKvM8{p=j14y@5;-z zz{!rqmHqjC9CM@M$-vanbpaIfp8M?AK_zw)ovo zZ59VMldAWp>lK6FhYi;z(A6~v8Jw@5DRx6shG{xWIT<~7l-**cwHEFXfw(U@gGM={ zmd|3o?Ul`Ac9zP!Z^=G10nv}HDH3l#LO z-2H}W#J)tQL34qB_}H`))nQO)Q%im=srtb`IQ0Z|Ui*e*+054mhgrk(VEQT12bh8k zB}rP(x&?n+OsV?*ORu&*=N*BFNnIl7>%I8~s})veJZ8z@(1AvO_Ea-!yyHxe=Ub-E zq;DZRqa(&5)+d{$Rxfz?bYzK5;q4RH7dGbZC-?>p^B4hbp1g40#Mau{NoVA!Z3f># zoHy)juhwtaaC9U|w`VM_23zMoS{B84!eS_9+$$@77PfD{``$}?WU-gh3m37uQU2r} z`aPZ_6__y`5V57NtM$DH9QpP!SSU?gI3a|drl3gFD&gly<-)gBg&HO%CIysVH=4m? z9#^OQJp^tP2Sa)R?I6u4l3|Zh5-aAo7NOHm!`m@grB8CypZ10u$3%|<-Q;=qiOhP$ zqoLb2igOK72|Zcd(f!DB%J9UO!I>9cU(~RxqAPeTU&iDV@Ygy3^2C!pA}^)fPxpr9 z^gfHN4VHsi7`7g~O14N;A*Zjyj1#osh56Cgar;JRv*B(_RG4+-)1e?}Zd_gN?O zG1134JqO~Duv5%!KQTqRs9MB!Lt<0e*K6rmxfmQ_`y;JlWhYTV>7rw=!Ccx;6la6)HACkFb7v3!G`8&bOjPy|ueBL9?LZnp3-0pb)ZoW+KK@YbJmUEB_^M$zh*-$i)A^@SGtXJ%EHKE{6C&SxHg{u;%dR8 zgo-EEL%5q~o(wYu&Fe}y$fN4iEyrt|Un69onvtGy6XH70W5}Zyc1X2~OY;XQ2U|h8 z+K)cBmhbRf^Raj-O?a+$Qh)tPvg@ zf~3%z_&v7LKI;l?fVWXQ!pyp`_4TRjwS78>IJxxTtnjE-6=|PNGe72q98SzTW17~% zdX~h48@I_%<3j0&gu7-Ru1)zFiu{cp_#xumNe3+cV38;fqTA|HPgngR;P|p$DLz&p zXSwms;Y!}O6P1dwfO+x1&FR3Hw=T~$#&aRR#eBG#piB5!l+m-&Z zBf%4X!g10@NvcOGJ34MnVmG(@)^HIe5~5 zF980h|8f<2{>uf>iZ>Hzn|YNK1gq@z7S4uyvGX{REm=SGCSyy*^V97~DIeQ{Q2B_X?4S9xTg zedh5Hb(mjM9p5W3505<3PVq!mp^WtI9JMvmDf@zw*~;roXB0j8#rJF>P9Onr>mw`* z6HBF{qe)`=-O z%Yq3d>(wZBCxoWDI3ry+;tJ#ZDR&%axaW(#$m-Vm6I(x~dm;|=Ej1nynhC`PPUbr$ zJ8DbJ-)gB^n{mG)dL=Nr{#i5Qu=nZ7S5k~5AOrt%V7Y#yU1?v*#R6JK(g@~9wADTU zP0+^Vt=l)pmlP%cr1<);hBoVYg76fb{C5 z_q69jfL@Kl6r&&-H_%7%A27D3w=RtCvx3 zO^~cBi-Dlz1r0W%BBx~HseF8=31(ECG3t#`Y2P>%jpt>Wjy7Q1C0O>pd+jLQjLPC6 z(-vR)yTgiqxXb*5#HE`-rIyUJcWEGXWsVk@Yp3Fo7oK; zVnS>L-my(Qn5>GA^uX3u@%tc^eEpVbp&K1X(lAe~UU5|6iF^;;oJ7Y!1_e#`r zUod`Ufxj!9&yTw@gK*bo56&0u)fYRJkc*runsb!5UC&jz)$GT``w=HQq%elxLIw!} zPx7xyu#gSLfvu>r&i)a%jcB%%;_jfJg%J0&e$PUU7tc$pLbjtJc~{n5&MH$IU~gko zo$B?Z#9oc*-Zqait|B#n0_o}_=c*_){*VQc@>EyWiep}hN-Rc2)o)?8nIKB2k3p+b zU1cC;8N*XRiOUmQ8WpT3>l8r5Io1Yu&|DbZxv9db!NoM$bKfYM) zgg8b9d2f8;OLhO>g39cPkmF+(`$a&hujAp7nN9C>N1_*OaAfFXACol2hkuGHp<|%5 zz-8A$Hi<-y(`1m>ZU7_D(X3ENJ=+Kk7k*P$$q1u=;qlOOfpO=?bxHhs!HSeq+b+iA zN>OJ_prOyrA>L_~hH5Y|4`n!0Q?E`3mHM;(YTK3Qu9ISEpq~!HS1pPiL}Y{5Ry{c< z;t*xj$_)cS#t(p1)C?forP4>^N6$vdB{FIX_@M7|X*?Z-m0 z&W~^tH?n`&%@01~R>n~dnjN)HHhK^=iC-%B){!uIQbL6I@t>vEDT(z$<2ZPv=h+y( ztfhinW}rjlx{jUt%xh$Q_Eo(UY;t0kt6Y1*Z{Jf#OkO$6iy06iVWUXCY1V;>v1Uf` z(SGHlIEWJCcP~)`BbJl@DX07q5D=n#yb|;L#)sqO^7>G5zNFbv&++HcuCurNd*{CD ztMz|9pTjcwoaQ%ptmJ+l)5M-g1ZOhbRPXD@N8SGiS%PY8pV)gu1TS|sZh(N~4=f3i z@B&bMTCz|AVe}h~&nMl&m%IA6_mt1Jc?M{H-zx!h;F3YfCpVBk8E3yMx#a8Fq1*gu zjgqV8(z`2Wns;8hcG->gF*Jy}>;Uw*RUVkGJaTbw*HQ$@aynWA_+>zO#II}>S4kV> zse_*DKQKc#~tUddbpL1&fZ?&UQ#$6w)*&nAWMmThlZQbVM?l&HSJo#v+?Nu_v9`poF zNli_*sAvN3{LgVF*$@q}v$}l~H}6c#$*%bvaj7+)YZmfi&Nl<%$WgcQB$m8e13(F| zL9vaTxwL0?u5x{AR8>e*Y|30Qw-bQ?$9bIBjSwKgY_KTL*hjh$VRSrFZ}k2}QQ!co zclr#6#eOhzytn>``{}<9BoYsOQ;M#0b@Yuu&qRV;Jn4Jp2MpCJCzH;1lKrWnsQ**$ z`iEov&ow}7w9b-*q%nZr?b5bOLHv617!QM^QW$jL5*8>K|Oj2Q0qMXq=_ zs{DWmfqGSxy+n%rYgCw)j)S()*28kuPk{%D8v?6JM`FWlIpX-&r2sv-c+=w+Glog2V16}j0HAWIi z&Gy%jlPGhRImK<%&TC4LW560>J)^J8jb|c3^&2Doy#fIHoTdU`q*8r^{ zPdTfL_oN#28wM`7tof<)_UH>f%n_ua#2kRQ%5)oc1>-+81b=eUq$qm8^Vp=zx9!Cv za=m!*Y|2{%qJy~FszXSXol_n-oau|_aG$f z3AkT6)(9<{kiS`l^L=uLOBINtK`juWDP)^X)95xLp~$>D;Wce957XfH`j3ZgX&;&w z1TLlycQPz~(J&~E3r*ze)gDNo6c{7k!7tQHBTK=DDXn>*{*=mX#CzV!y|<;GsyA2iK$f8}G@ubzdm9ecDuEJ2J=-njOnFL76<}cm&z54H3P!<+Ltr=A;%{vZ=j5&m~=6CJ9&NVr&B6Dd>>A=@s zEhkO&z+YINbNv@@GY~8xvOsM02H`r@iq|j!f>$g+Rzj(=vC*i3*Uc9HS{Q;dv4xi7 zJA!lcEy=)*rcPNOD0d$ubd7ZMRW|(pfBYrl=%}<`-RF06ZTR(L$3zQf*h=@jBYgNf!(+tWKp^t6>i{|Zt4*X%q-}_E zC%7u7$+SdY7v-t$tv-6)D$3I|{hHZ%$T~Mh@pJd(N^ZlB`)bn`eRYA9Ip(ute4!0v z-kJpMZqQ6d(`dM~*wYtpyog73ip5Dr=HP}fJ7uI!X$SV_ibMJ?7Cf)?yXNDW@?|I{3+)W{+*LLG5!tu1MPP&wq7|wkfBp91 zjw5_czXY7nEEpE@h8EGi_t~o+(4SD1GJDxdG|A;uYm6}yE02ko7S%Tj>d=s=m>RKrQ)p)xk5%sdZXV{WL)~RNfT866WMVz);2%!=mXI!C1q|-knihteZC2h9cY#5$^tCbrHy|+psjvY^Vko4(320(W`Us&e~RWL!XRFMa|*X&QRBPq-rt(W9KOda zkOzM7hh%2dd@5-IVg>1%S_A?zHWN*BuIa5(=38{*?Vpb2aMrf?L*O93e;>-*6ad z&ldYRQxr|0~*6~uc1Y78WGan3ox0AP?TCmFG3g#Tn#P%*1r6YkNB_C&H45RXOvqDdCbhWRSO3V zIlu!Bo0I}57VwQQllkgRW5Ydm26R^pg>jYW%_-oUb!z6BG3hrwweFAK4*Oo$SM_=! zG$)JP(I=^|OXSCdO8R(6a6RYbUY|+@p4DXLtq+)+F_9ulX<`kW5|wk#j^}MN&md*u z3s;Vo640_>WN4Am4Z$=kc{*Z@T6W#7Njn7vituX*`*|NH)Y8m1bW^C&J{v@9wm|Cn zF>kbGUQ2Se_?~9=`rCGNCF4a!mMgFKFbOE2wgWEO@@cG5$$f#)jNBuho>SAj14Y1! zEt_rH*1GxkUIr0@-->|sa`8!Up$-|70Mf7pOn~rbTB}DZ@@w2x{ar%32_roLMNcKB zh9urq##3f#3$wr8eS@E3Dn&mAOc?-T>o#3@-p;dJmw!z)l1j|Hvx5-M_MhB~lWHHY0LW;P{D7eZ14|dV9dR&lDUy&x9r?j8+Oi z8xThzr2S8Gy&z?`kg~w}B1(*Ty)ma;ab$B5)s-2|PN|H9qwPYg7-jw*(4gC7oIxb6 z;6n2nW3_R*ccsu)M0I(mut`(8b(eJh{V14_r@axZzLG*-gq&f<&_-gAIIh@rSb%Df zM~e0yF|w}~y|lG8Nhrck>DbH|M*2J)HEG)xjc~1Kw0n(W{{VoLBK!Q;2DZsh`+vCY z*B~ZT!6DIOV-3z#^A?!`LVA0eDW0+NI9%nt7|J+Lz?J#S3B3EDgHE+x(X0epFYccC zfBBI7L!W#RL;LF~P~k6HX&j^#6rX^HLRCdGQ}uT$y0Ci%RQ^^z{_CCpA0K(x6)OpR zjN0@86zKKX&UX31d@x-2F*{wTbs`@aP8pEgVw34{2TVx zCXaEZgl>&!8Y8xRDz{_2rnqJtUPD>#0jo-$lh3ZfMa?s(RcEs!HS?p~^{Q0f6v(+^ z0Rvl!Kf@e5iEEwgz4AA^3{cm0|MLEB?j)tSZXUu-MKj;Qav5YX(Dp49Xuuxn2298O z?T(~`5yI(z*a0ih3F0l-kI3Se6!l4bjCjZ~5~`Z6$zLEcNM83B{oem>EB?nlm+^xn zeDV44w^NN#*yaJ0`sSrr({ushNAWIu5`f>{F=MtW>hJ!v+0{gXWTb()Caf3aSs!n` zCo}d~Rmj^Eht)Bk6S(?hyVFfR`x@Zn>!h7>ax0wWR;@;X$o}(Zr)9u`a09NVVj@TiM)6RCB;6XL7 zn~Pj8*8CC=SdTNcw4hlZM~>1u&Eq+#3E0O#S^{B&kTJp_Qg(my)ysj|7a$dtF_hfX8!0(DC3%4`;FO#y07M zvS2l6-U&dax+o3JW32=7=nKRrl{_FsHiZ!Gs$z)doyjS2Bm_`)LE6V#H}rs7a41Iw za06X4;>KEE%R5!8TI!1NU48%o3+ez;xT}4KNPolWd}lZ#{x&_RqKu$_O@FJMR`Xs- zK1BtZYrf8GQIAG^AW(vh>*DdQn~R!vIC#NRGyKRc8KCaafRe57aXoe7TOGZjxhO>T z`U$5U&#for4sm~;Q+>X`tUS>8Q|(zw46qW%h6YaNR+n2YyaBAq*Jq97i4#D-%g zg9RdhI!vesL`Bl34ATe>9+8QII&PZkn;(B`p@aD`GXxjI#Pe}*I09&o7VCjh@J)0! z?7K$S7JY%#|4m8mreBeHhx17Ef&@Xro>jgak9rKgI1z#`us`YRun`G&Vq+*N5r?n0 zU1CqJ_X=M-i=0ZW3N=82S~jIcDCMu~%fxjFROL#Fy-J|9?wCRmC~^`&Fg5o@bfs`I zC1!M7{-cIBphM`M%wA1w2IgKq)ft4UamTAVKITexOke-5^nm(c8cv$MMQbX9cHgry zq*ZqjA6!)FOpIh*z@D;nRT?o%$BNAx8*83?HbXh;)l}JE;I}2P4wRl*dGpL(ZXoi4 zQ9$~Og!N&B+%~9)HI8A;IK-ojbO0o<;YqjvQbz21sM9{!U|JwHytQ8YJsDW8H(-mo z=q>-pwqHb+D%EH4f6GI+^w^&#F~k6QPGa+)liPH%y}op^+g(!3sj)xexVY@a9w_K# zwkGP9W%)d(X9zfO##ye@&VvtqJ`D87KQ5OFW6P)D^?L0ls z5lxmkU0^4^K>nPUPa&H(b~0>G&-Qr$io*w(XyVYg%ms+cB9z``Z@mwD^-EzQP>541u zrbqr5p3%Z=RaTFcy%n@h@US?0n%ld%a(#I*7iuae7twyV3f-^F`T6bq2uhtia1coA zu{nb0pkmJ!9vP|JRB3GWQvAUq3V{T~RH>q#Uh?iz-3+De-Q}9{T!X)NjZAcG>=%!S z%onJuvrm4WI|@ENVY?Ax)Nf30&e??nek*7+Vr0_X;E#AXuZvKfxG%;$+yASW?0=*XEsFZq%UE zd218xINQt$)^0hS?{RLUY^!+PkZ3o**rcylZunw3dGmnr*9S26hG}c-a2|(5K>Vw^1qo*xM=o? zii!R7;e!Go5|F@`;Y}3BfL%4p$_hctoP=nfQD6MHe%lum zg6j5=?ZnhnmbUZ#7sUDR*H%6Ay($c~Iz`X*DMxJSqo8p;XWXIcTH{fRDa60qgaSV{ z$;BeH8kC+!#l}5TPnFl2(Aqd$#hk<7;NiJQ_nZ4n`t5axA3qVLgopq69#?wEErFbF z7xliq`-q7DIaR{v$!<7HFJM*7iFB>hnrpO7Sw4w7OF0F#X?hOq&KtEiu&;_(XN2u3 ze?EM1{jJWoE6im+hATZ|M~iR3*+|AtuuY18z!^+MLB*8Sr%2d{d>1xqz--=zPcoeI zS_IVlEqyNclfu+->hL>=`h$4I*{_*|M=uf%sSth+>>)MzM)p;6@Pk9>?Yy>mQA<)%jA*0`KHpw~L@O%(%X`FzNto9qTjvKUZaZ$za?j?F&q9 zwmH*TXcM(&d|9X~K9o>-ND`M0h^}!d0K43M(ic{*VHEquSTFEDL zf^xaD@7V(u>T*AA!td#C?+r=~h&Mmwy?04}Qv1C4+bgB?RBZcLPj(}T{KscYLyiVX zU+J{tiUx{K*Osrx_vfBk6lm&%=|DY$Z2cO`yS@9qK+#f!J_{o2z{RU<7GJy1^&!AaDeK;# zQC+rm(A>1}&7>RGEc+lAx@qn1^ z8N+U|IaY-n|H}#w(Luu*{!mSgl6CyAp3$$Ni|P~r)*+Z6fCC`lB7^gz{NW%aa&zOr z7N@$*vxUaVEW}vEzS)%i>((O9J&m`b*9v?9w3`=q_9p#xWT4SPVI!Q{l6RGkS<(wfG?l*aHtHaryxU(i;l-az+*knMfV@( zvGkKJo5G)H6?GKJ+&dYvJ)(TL=Ljckt2Y9^hA1)=eYCJi{x*`z=5~jY>?Ood_hNXm zu|;*BUM#=r@2&8KJO4fI-j54r#(Z6oe2TkEtElTu?d9fz7NP$g>zGd8)(v7tEkGV_BEH|p$YZh7p^xV!Fb-+--El7$C?)Onl0k6 zn0e#c_sPlpXEF(CXj}|QxD41rN5uv0C>Sed%k7DLS6gfgCboqozFxaEJHZ56juD!` zIv%-1M-Ts^=#^iZ>zz;j%}`f%3N!PqNOK6YRLr##@fl2vxp{fNdC#WBdv|dYeBMQN z881N?f%OpJ$@rmF2%;@N@HouG4#;Mcxj5VQ33})AZ!LgDWhU{nM6-Z3JRZ!vWhl6`m`kG|AU=N%!LWRZWQHfBYgjNS=&K}y7=`?OuNjA{SA|LO%JT^OO=byqq_cc09=YZuSG*W)fI(0W14vLMiZe#3L` zA|CHFpJ(G5!qceW_2fXzTUlfl*@SX9Z#yVXTQ|Q85|Mh%Eo`uZh1^k$*&NP5g=h9# zqSgJB)OpFMy{Rh4wC}0#m7Z?xaCIRGFElFiTP0I0g<{3msa1CPNz9j)lwNpm{ffE( zlk}(d7W;l)~3uMe*V$AzkC@r|Ke9Sj+Y)p%V56Vk+sH+8~VZ=gOuPl zJu@w~S8b)m8P!j(nnTcMh3bzb2Nooe3_OVvBp@qWa{lX&_$zO&8>wo8CW`3iZ0s26 zblLQ=#;O`#g)kJtT&h>pzTYyNdm!gMY4x62TG%RLW>_XM6ks6{N)tt~j1SMn7eaa{ zgBeK^`2o`fDU^Tu2}V`22MGt7Z{^B~8pjV`jH}a^a3bm$36*SJ1pI-sv{&ZOL~*|a zEB>m`uflCL!f^lmOS2EQrtiP0-01Z-QoRfeM-3o;DU5UNa2n87hxK4eSc(roPTo>* zdxyU2K$ZE#FBP&7F%)U|C2QZX)bNd-Vc;z(%iT1q*-qbjznP-MoUn=goI;VKnGnZ(FjWjaCoTw!;IV z&{3yg)6D>>cQiolf)wY!rjx!dGks+5%8mV07>=G=bQu88F8|CSjD0-V;~V*VtM%98 zcIhYrr|>C9M)QqQ#m)ZZXlqcrqIZ8&JV?7z(Q0O?v(QPxay~S3Yl}r(cSA?M%B}@3+iUw2y!fuY3uhr<_GS>X6vcPlV$q34*L0Vh8KqHDEMOnMcM2C3_PUy@^m9mgDGSMvMg&=kLN zT;}*f-J+ao{5`wC6Dwq+@p|k_?9hw0!k@;^QIL%{9@rdvWBX6p&|L2cUe7NWsyaP?*rgLW%}G`i{p@XO0g!6O@wc4I+#Av*7g{$VW=1C9$l zpQkovEtieK*v!Esx<2J2*}SiX4AP*A%V?q2QwV-per>iZD)l`xY_*IJ2+D~#*xKWG zXF&Q$6#L#j>Y#30q&?vN`c{&|nMH`XkeO zVNC>ZgUtBRMosi}ea+$tFVp>_R|(HgNH{*9aJB;)Q^^<)PE!b&)Cnze6e^9IOz>BQ zY$D>_BZM{sZuhef6WWh9VThjx^WH&+1}DWuS#S5Yh&OIlMjhN>&3i7LXSEMyu*hZI z?|;x3`Y4^JwB8>ZCgHXH>d@L}BnY+jnp-ir&NPL=by0Aiy2bbOQOnhN$YD*urIMB5 zhfmL5d{u5J)%|tgvk~{P^x!j~mc3W3u{m$v z_dRV@j5k~Y^i|3Y>NvM(OV@-pJcS5d_BR5l1AVG(HMySADvLJMja5WdLjJH$fM?QM|+NJ!xn*%;z55Q38iU z{?m7cgwy@GM^-pDZzGy*M>vhqm3gha9Tu9=&Z0soj(*5dwyR@9VIM6+Sg$j*{TnG2 z6+VZ@BxB0*(P09lgfCxzSmj-380aS^Y8@sXI6k(qD6|Ma7Cw(RPyFD>Kd4_BcJNtJ zao4$ z$Wtz+jdTyR&K=*EQB!sB4?byAn0Q@xN4)Fb(vl5TPcx4p_ZZmC@ zymO60<-xe-3nLN7pZw8D{V9S8&3?4X+m|H%T=qLP zwaR8am57T&RzltI3GZI3%ltA1UwG8&<5DU`^g#$ibvLbe4{bHa{Sd~L1@5GZ!nvu~ z0O<0Spx{6*<0Z~`!_`be1j*EBjo;0Mx5V9evFNGFoxcrD!i#K24|J&xjt_KhM#t}c z=q(ub+HewUeh<=zKb<-kh(dSSeEO$0?@bz;9|Jpby`;F1~y_acM+(FV~8(w({GG-{M2e&!tax z`#i~E^@7h|b1t|mc-dgysvw@7evD5PL_ANT^KN?*PuXAh+{PV3LB`o|7^oH>McnNP zA9>F6f}3An@ZxF3kfVtVFa~SfE{}a+HH?#B{{GyN|HZ%dse!@kO1o3m3VbSvyrHzvZXjZ-kHUFo7?X3=g74q3Msd~3_z@J{}YTh|Sc1}uAfBRZ{rQb$5$U_47 z*ZS_*9dFmD{PC}Kzjb#tPt=d}bjmk>6!8YDLW;F}|B+M^fex^*j`XDLnqn1lNDm}N z4zwnFib~~+J0T36N@=_oGo`@9Q%z`ySm{{zClSbmjLU_#05 zcz92g`|!tSh(sjuY+`g%vlKOjTV26JN`&Z_o{6Mp7m1`2#uG-13B#k62kk=!!d$3e)1{HA!p;Z=XH`|4(7ku>hFn|Rlc3Bf!& z{E6itGQzaT*oY0kY^&p1>Q)lG8@$dVd@m#2WuXY zd!r-AO7Y?->-D1HQo_lr@}AI#nh`$%L@>!?v`eVOtq}5ix5>YHx$>nI_WElAES>1O zegK5I(c!(sqiT(_40GvF>|gee z=bDU{xKt6xlCqsU-sl|Y-xy4hPmXW<{q>3d*HOG;$@a@>nENsY!Dat_w#iCeWt-uP z0Tr9gVz2%7%LuCmK*EYQEPGkRxlOiz38j8wVDl_8w~tG5GmJ4rMd^M9jl=3qPIhnx z*2}YI(0K}O`d#=52Je?&cgE)*`z}{y_Bb1meFS2(f*)H)E?~9RWpt89LaumqMxy6K z6XOt~k%0sxg@963Ck9H5rAh~qsFHd7h0kdLT>DaZJ3PhYlQ(lPZQJ?oQ5pl;#&`_Z z=j(&E8F?%7Gg{F>!P!e<WtO{QJ-B}ANJ1`0RzdwSG)z`PXmJLI}wNq0Ux;rB!r>0BJ2UYoev zA4^{k(&L|F`SRA^OV_{2CDNx3zsDQ|HM~h1Wr`;VVme;|8{rT#NEF}4fi~DLMn``7 zq+{hhkA^HnWW+5*DRg}O_QK2*%3ih^U zNA&*kKi5;D1efTbkyXntG^=h|%-iCKZri`CGwxl5NRNMbq5_WVI0?jo1sXxOe{6G- zJcq;^F&Xf)rwbm*2Z@=|2OBbF$y7EKu7gK*C;A^7w?9?f$3U|l42tR?Ik&!V%J%Jb zVFrVGJE3W_Fcq3rG=Cez)fXC-2vQ<6N85}UgK^IN{Qw(R7h;iBUaLpKL8iasn)rS$ zHQOoPz4jiUd`F_{DsVsiI-`w>`Pbp2Yf0?OSw508s3Qdr>>fAyrw?T8HRXxb!`Fw$ z58*BEk0Kv(rG3U;x2;EV`5*gB&T!fcm1yQn`;lu+k0ICM+=VCRN9_9xycZH{v> zzBy-0>Ijn)9ot|iUEU*{+jbeb#D?d6^gU3XCs4;cHQzn!!axb#`rew{6xO6aYBRBt z&Ar(5x~14Zl8m_5$&glnBAu-y`%$y;M(HNjG$i1MzpTm#tP?!m`Ty|sRzY#L?b;?D z2<{M^AR)LrjRtpu1P$&4cMlMPyF-GzH16&eB)Ge~HPA56`>t8vKT~Vg>_Al)#Rhcs z{oL1ep2zWyaZ%bWRX~=RF4V8_-K)<)`qdeJe7$q?jNwoJ7+md(HoN(^ve0zXWYSAY zL3M~V<@IdJ5XQc|ws7XPXXd6Khsh#u{2hAsCBc=ijADqfK8ob+D^DeLR9+7)>Jy|s zcyK3JVi-J_^fg2)9+k0wWZ~Ven5m-y2l(wy^4AOuf`_GNKQwuh^=QRTO1^)bgZ>WU_7~y$IW5*9)K<5H1=Z|Ao?35!K;=s#|4N1dR_Z3dYgDiA{-`6Kd&Yo_@8h4#y1@`Tz1BhNw9~rXIjZ>p9zg17m67Ym zuN2ZSTjf3e&+;!CNdLPv+A!T5HvkawJQM9n+A||3*By;#epQQ>!swsNad)**fvQd2 zv-|1)567?`5IA&J{4d9_S%nRWuT>hb9k!Wk{(l>WE4j&!j`^bAr zcSh&2jOxu64s?r{8?h@li)RHEa1y!u5aC+q%4#j_VpjY%zk)^m-=7^uDS=Sc+ezYS z3QQ8AtA7@`{XOB0H|xK)9o}<%sf&AmuYBX0^aQgg>-VsvH!0i5sXnE zX@5;$SD>@XiVfV2e!7qx3PxiR6g48=<-x5!F*TwJ><3;rms{b@L7E+3c093;{f3ko zW!@I$J)ptBdl=I8(X7J&7k80x0t$~S|9+Q^PQ~rSCDgOm<5$-tiC?r((C`ko^@d_Q zmXb8&G2?t^60|>r8v}yFi;(`#HX#1I|2HKk1$7cMDMXvu`RzAa=LXL3*pBo1N>5`+ zCuE6{!{tDS?gdliQSyw`IWsX+-!sm9p@daO5t*myP&Zv{$ zfz_PI(4SN4C6!Yv+vnsf?q^3plu8Ld+5{*uVuaaMv%O&*V3=X4I@$wR-S<9hj4q4@ zv9*o}I&_$G{1&_W&xoCi ztSB8#hN?G*+T#7Mw&^K4=%JzCKlU!&|8nPu6Oy-Z2q8%Lf}{-q6sKWb)g6i z4}6B2O|*qjD$*dS@e*fG984n)#&W9O{ps!Y8gO=ki!}fo-iRa34 z{h+()w7djwATtS11c;pFR!4D~bK;7>9G4FROvgxxFwEdsEwP?&tK$qPFWb8sWbkPX0 zHhYVJ1h_%@t+R{y>)Jzk@J47BH|r1pv3UAGOw~HeS)IS?m27%r8EDx{V{xumR zbMgv>?t9Uyhz3XNRa0*SkzaTF7zt=!eFn+l_AO9p!wP@g;6>4GmCv}YsQvOcDe(~;$Dfi+3#rPJtFew>wT7FTGMp>dyd{m#CH9gfE#T^PS?yLl;}<)yZ$#G~ zeCs7U`NmiEt#`-Hm}#MWgrwwZ9|{Z!#rk?U}7Wp!bLV z9k?p|UK>Q=2X5SYn<6ZnpX0NS>DLlhXiUjY7JLnQzVbr%!x5LFf>saCv@%R4GvZi= zCvVX$wN9mP$(iGP9oX;J*Ls&}Aa=1v@z)f!H7T7`*oxj=JmxNysnk}61gHEdkAiXa z5=O)}#zSijqH1(8$d)WP-*YV`o*gyf*ITq@9vKu%2#HxH=gVkf&Jj03{KCJECmdC; zRC_-fHyQK2RIa;e`^k;HLgmnfv>J2Kst#fe2@6bzXmv4yX!6lWSwCw)Fuylxa@CeDd%{?IgNsp~ez_pzmUCbIX<_(f02(o7{Wr5C?$iTQ7>6 zLmv}7FZVj2Pdjx=t2B9No1-R?xbD~H2*a%rCUIt80k#?rMcA-iliP~p{_52feISan zkInNle)>)cI5B5@)Gi%r7i%RPY=CJIFU2LFuLm#7HhjAC`rw?zUdrpLA zg(J&}#yB*!2a@5k@@j!45;mpMpS>+=U{j>EfjIRYA$sNB;%4#9q6W3t2R@&JAH!(s ztx9%zonEH`i#5Hkl6K}s;n6+Zq_tS^iv_3gSU8HQ^-K=tiESM+qQ^63f)kzC=H38e zo>9>Ke4=cx%-P>nAhMfVd|piHg4yD(9(Es|H-h8hm>nAxaV9tO10K8G z@`EDdRttz5$orxxl4WlMI|=x>ApJJ|y6E!+-?6VBv~W6HNCYNK z9OB^gImx@UERp4xw`&J7vVKr6m|X?saKBUfuLH@V@qar4^P>bQyo0pF6bQuHRQWH> z-K?ptUWEovUaQf)#Yi9dV$%}Vl;GrpQIFF3?x4|)P=BI_raMC0eog%RUAwmR?#o~_ zo)YgF(^2|mny-qv8uo_l^tItYWgGY)vUyJ9E3tEQH7;27tx!ZeL?H(6bl^87JH{lV ztHPmzvNjS%dRpTGX)ys)w8K)g6+?}yu?NYUlbDgE6kdWRGGHXlmj8Z9QFJctZ-{9Y zznLv#col_(lGQ&B&DNrGL0Op1XTbye@B;xjck&_CKnr*SQzEXuk`u1W?}GPW9UH&6 zMAq{jrfTsC6YMD*gMGZ=C4$tI0rXqR0lAedPFkjqYd&l0o$ZDkaW%BRC<`wHPJ`+M z<%Luo2Q=QDaNsH!b=QvS`eT)7OxpU7Nb}0=4Lnb_^px_%H%+Z~p%qqsrT69(i}obg z>6-0AfOLsOtm7{3%7v2)5g-Y58T$ny5O{@?K$^e*wKqBQpYivT(}RXEEbyK`I;S-{E42^aT^@qAhc(k$2*!X ze4O`K{3P_jKBooU)*?-u#5%?e?&n8DwLeA+lN@Ah$Vgow0PD;59Zb59SoOH@gm7qs z%l2wbF_|z7(0W>46_kR46`{qf(O*GQ%T06add`{TmPdw9t0FpuEKomfa_?L9W! zLkc3?=%NLBvO9fyw53q|w}&5fmdjN0ms?dF+xu42g;AW2yM{3$EUfL%>7aTaJ7o|g zHL~gI?aa#!=j1TpkIYcsH|1pumfcq>8m*n|q+xBpO1J6EVmNPyCiA~UBmif&u0!(W z{hA%m`P5)e{JxARbqeJ38b#H5;e54%%1Sb={HsRT z+l4m`v@pqg(ohDyI8>8Q!$3GG%Szt-rVs4C<~v!Txx+DuDeve< zNzBB^*mNxsmxaK-(V%M||1`kw@YDBcb(nHoSY@Nwrn2KBeOYV*ne}WGFX2BY8c6i2 z_1?a1m5^h%wZ!SPm?W53vlwGI*yP-4?VZqW>-krAm)|Bqs%&mzN;{DAR;&S%NQbfn z5?G2r#PKnw2BXcbmA9VO6<-3YRf?hk$I-gKXfl&-oOExA6UR%*sS>*+GHd0!^B!|- ze!gjEi9nbUa&Fn^LS);QA-;UB{vfrEGO zGKB4u>%=P|%UT=KuTh zTvj%rN!7tfQ|iT&-ijA9c`Uo4AD+67cOdPV?Dnn-2eJ(gXpk=rzBK2pqKz}0NEvcq z|1CssfTOK8m>FT$jmju$gaWi6RJRp8Zye%R>q3bKh;l`sd7`)__lA@@I_3b$7kQHZ_8NFSt}jVapox!{;@x}?=$i~>cW>S z;^J;Qz6iISRF`|(sf%RcIKc4J?zPd=g8AJ^5G4PJEe+QO|qf-_gX+tR<7euG$g z*87=pLN3^Td?1_0S9(cb$}g?^>B{j%xQ12LKoE-*_HJqkf9L8W2JsQZcW|c}I`|xd zS6v}AK~JcK^+s0gk%N z=yEQS8ICw^x`M6~Zu|Xlu_pdT@$%W2w+RA6ez@?j8Ac}RUy^O*Ch^S677^7d@c-}H z7+*9D?z@X@s#!_grCq3bF=s1j%!>ao@KDj{DFnHOO|0}B-bBZI(l&3cgmlH8>RpQk zMt{u`ILWI9%F;376eokdOtORGU-g%{k?v+dr>ezyFRLv#Rj#*EzDMA!h=CuulNif4 zp-TTB`enMAsyhv>({JOBKT{f*C(uNyHjMgHoXj6O!LTA~XOV$4#&f4C zGYjB9W-5`&ZH}CO7e}?dtln8AKoJ7WqNh?-xO@>3#HZgtZ9s#Lzb$p3&WgHtcT)`j zf8t~tm*{SWWtpMHymjeoT1%bS>r&BjsU2wmu|2frS|g3MG$_K3!mnkpU! z9Qy19oa=0;tp&b4)Sv!W!k3EXf7zFjZ!_#e0Z3`5dl+zMlhHP_K9r@$@7Zx?iOZL- zj#{!Z# zIK&(-O$>zhlb6@M;c+~b56cBkiv@%xYR=z%u20>s1R8Yd@!sGrE9O~}5-4f!kx9>sw za*dT)G#z^U+ZN<><@7KaZPTsvLtGxXBI|o1COn)>2M(j2+}HER)V=a#=AL2--uGuI zc1;%iQzu-Ic0T4JH%t1zWt!Z}o%nupflb&l9?bS@Z4AHT;fGAcdmO~3i&f#R*76xN z+RRDjDlu(aDFypaZI%m@W=lRVKkT{r@!zVO&sBeT*oj-u3N zu?Hm1&gx~H0%DH-lOjpe4;g~~s+E4a{GP~Y@BYYBU&h1vu>?(YO*e+|zlLl+v)Mh4 z0aw*`0YsXZsC&{QmBLS=ZcF4h5UPIytL(W|!(4a`hzLJxDDdCvJ^m1h_tcc;?54a* z*~Nhl+=vh26~_9RvC2}o3E=2^&|J-|i`}FWev?^J45le_C)oyVO}gS-Ki@-KYHdEp zC;G>9xuhwCKl(%i(@0(sMgtUGe+W9iUXLQiiV6>Q6WA?@rRw>utJYg zyA2<>o$C`?*Zq?e&h6TmPiiv>T>mkaeQZV2D-ZP=hmuiA4DiH3dd7*6Tyds|R!XYR zymZo77c6i-O8f~}R%2;@7}iZN?N6}DisrcDrDo9+5D7)oPZeSwY5@~1YH`Gd6fglL zI5KknkYT&A%g&3+6=Lmo`kIE;x0Uu2X2h~O;H#4Qc(-4%HB=Y!l$}arj%{NjgHnaViuWcpLw7c6RwB>%%;lzAM^N3j5 z1g}~ge*O~1m6=Rm@omy44d((C~AgxX-lEsYCAc#l#^yz2X>rEGz)(BMZahY=^V!MT$_c%i9GvQ zoPJ?pNMIQ)GK@#3sg|UIkGRBylb54HNG^tT4~pf&q4K1)IdzeRoHWFvoqxBDsnRj{ z6x7$#_Yqf&!;=AK*c1Vo7IUuD$frVXJoY!R-8;I6UFc}ACKYk`dUg4mhPYAio_i`M z@F(4jylXh@5^+}*JxAjSDu;8#k_{F<3ungP0K}@u#U#qG*#6ymucTOEB<6+i1r6tC z|DZ@G6YLoY%CX4eNWSrVF@wu4#@^-|hh>amj#y39; zxmW&7+v<8r0{D2S$-jiGzBX-a`U#cJ;_6X*kvyP*>yY$u1Q>Es>_iSZPN2f>A6o1( zm8(B|i?wTWsa7Cc8Oq>x2;dLP0eBPSPyCvLHHNGzCwaxuk1k)b98b2j_tka}z?FUr z6oDZ&OJ;&lr*R$@JfP%f9ph`?3Sf9lECjbVbC=7O)8<9&)DD1-?)>G62}%EH4)n-y zRIkkcsJ7DaW1;ONz4Zq}>1?DUM^&SRaRD-Hu1Z(2Ddb>Hqb90%l!ML30?{^aPj_zz zTkMhN@fuX|WTLhFPiC5$H2q1B8+thgRSlsDG`TNVOQX7BrBq2xcEy-c@{UHNC)??6 zbxMXUzbsE`V(jq9@@kIwD%W8H5tTLM1G>Q8H07aw#y_t^7ym5NBK@yt-G!D|7sQYB zkx&SYLLT{lId7m5QU4PnJ^+$ATRrXoakK4-A3q zJO4($UKSl*-DA%aSdS|BbP}eKUj!dkahi`7q!{WP5Gh&vU%WUHZO2u0zz%N=Jktb= zM`cQeY^OQrFCZj4cBL=BF5oH$cU`H;G!AqV=GX|CL2+oJNuFc*#E+`KM?pod2{}E} z?17zPjL*dsJ*@Bx*QxH|AM$-VpW-tj=SH8KOCTwSK8(1iWgyOzU)7mL4N}T5CYPb7 zB9Y(Tv%5MZEZB_EnJEB})&sB2gnCTQdq~-v8cxa<;f%GJ!1RPva^O5H!n^Mo4n ziwb0&Gpp3E6%^c-9}l4JW=5}md#TMw>2VyVVL2T3bTqypC1ac}%S9dijhd=I<{fFUTfXK;9_-5p z!mV=J+C)9hH%ltU2xN=AP=eGF10Eaa57~AddPJSU-lv&kL`--k~p;JiCCY8 ze6gwtS~g#vl-26?#s$#VISWuaV>D)@RW#`%Vm}JFS+f2u{Tyf)L&eF?sB9%SpLxP@ z(+Tu@I+xwvf~#gf-6b*WHU=}*Df5LUEI0YKrF>*mYkvnO2(;}Za|I7^n;}Mk3BrcE zaKeWp9$t=t^Gw6&$3KD~a&yD0T8%_BCiLU^BsV+Vr-3Uvi{3(Ju=(l$oUgUTW5H_3 zqVk8$2p-un^>s_FF4uvJiFiL9<L=@WWr{$906 z{LOO2Bt_oML}4rRwRqk?@rR+--i%@^%A%H6qxfB{6wc-TmrbHIf3N8oTKhgm$c?gQ zFyIU}h{tMh#6+eFJkL|6`4sO7w$b8|^`ka?)uHy+QDt)O@NiT^Td$Kg9^nc^lng~Z z`YI^)3kr?3efefn)3CVyYvhzsc9cZSzOOUCVwkeJ{IbYxdP(6f4fUw2QyPOsh=zpD zj^C;V!O2GmJ|eH?qOu?!CHHNC`TEiHLHy$$XGT=`URjPV>mUy;|Id);ihq`9ZOA5$ zFN!O%G-WUCm0j3l`4ZwdRRzl(3k|DtT@66;MwnFN95oVP5_& z`!CMo>AP_9E(@I0`o;%T*^H|IkB@W73yf>=)gPnAA*_OqtV1lkGIwi1jWyM&+nq6vlHVp60M*0@f}?Qd&a`OB*SQ`=z#FA|>(u6W#&c-WDMZ_!cHM?-Kf2 zR77Jku>*IjY`%}FSSE{VinYmo9bXYxHui&om4nS!cYAgBU4q-UD?W%7~FP5~#m>2{AU^tCim8 zBPkfcOn(nswVXRnqcT;6rder2J_mzp=(8<_gdhq(3g4to&A)(&*JI>Fjjg~+nZ&MR z2jGT=*UucD^32g43>cEi%eWI2PU|o&J}=10QkxW z^y8Pl>OgZXC0(^uUzK8VIyG1n{*eSA%ttM^t3Y9-W1&z)<>pifM~6$~sD!!FHA98VY}Gzm^*6?HbCd5B z!SXEqdCv+@$*5Fgh>e}P_iRxjTOjQXt`*;A2np`d|Gy;oSqkgm=lP(IDAp10G?0X2 z6WR>}TJk~b`}|f$FT-P9K@>R{Z4ipfPlFq>;nE|WFXeq>81_z%pK3LoOnW*nX^=OJ zY?B15;x3@xzC=I-mu!1HAvf35NLCan`9||JGRxS^h}Z*T0LV*khjrownr#I5^@Oh_ znvH598&n&Q^h39^O$`W;nerTnXfYL=CT%C45mC(!nhEh*to$XCf9z*xS<1wGq}?zFCCQfHC<>l%RCiQbU6E}*Bih0M}Q_e{HJQPG+*n# zr6GP*dX9hVuVyAYcc$$knb3jd*XL>W=8Kz3VH$o09Uccglk8=+8r9mlA-C8}8-;58 zd&pPFPy8VxjkfFF$ebcs5(WFh3!+WV-S;Tc`BKLiwg409{d+T!Xn1q=4M>h;Ve1(& zy)-WFbrc1l-vtast%cASAgJR>XppX4RE#dn#{W9{%D40TZ`u4%7gg`io5Fk17cZCK zRaVm0GNb!3mBrIF^h*I;0SRJ`68WoiG-(_nY6=1=7A|hE0znon+CDN4 z>)x0yCD1G1ovG5S|LG!BFD#<|AZcbXT2<@EX&UJBv)}R{xST$2%qys-8%Nvgj<5IN z`p$OmWF6`!;&p$Se`13|iHx}uIIVH>|o>ynZAz|~)FHo-xS-q7P2r7Xr9M~Hno=xFpi=US6 z=Y6-qB7D!_5%)0-XF{jpezNt@(e&l4`q&-CUX403gyH_+&#c$|3EdQb4U0jG9tJ62 z>L^?7r0ekZ?|@uL5)4U}}6>YF!#A=1R5LoqWJyMq1*OW-x(7MYN%U0;)u zl)%Y#Owc467mb$pz@Hf!=*ZfDL*J4<4rd^45Nh&RhaJu7fS8K-r-aoo+B=GKe4$^l zYvnw*G`oQjV>})WWU+kaRKv6UA0Th&+Xd9}IVQs&I^OmuKID!!C$x^(DkH z*EF^>2l4jOD|aj&Tu(6jA)KAg1PQ+Gap=J%l`ARIxQ;a=yOSg_qY^lq#dCl?`E&W=$gVru9l^a<6i!rwcB zR8QrCf0k$nvOU@rlyEo|HE8Mzi$E~&=cQu~Cp3Kb8H>f=r=I3q#xaAj#!36O5a+3J z9-X0o<&}Jqih&|J{zO7IN*S;>qA?8#z;3-kVZu|^!;dvENMef@ez2wHmQ@3_eg-#; zaYLnEa0#d`?^)p1Hur=QAMecK>u3BM`luJ(7I*o~Wxf_BisJac$wm$M)4N=e7~_y! ze#_}p68hPSlBUli&X*PvBDSTd9Orb;(>2{zB@Vo8ZAIXR*%C25fxE;owl8EgUjp zY{q`*UA8c0|8%8!`Gh5$H&lI7}V>g~T z5QSS{V0{UAs9QY*A_?8@^`k~MHZ9Io>@`YK%`i2W54~D2I+0JIWnz`GeUTQ~VKPTn z7;2a%2Q@DNClf>dF;|+<5sqKtb)IdVEZj3#c5@~qt2nSGb|%!jbXcB9DG_l+cl0BS zupBE*gNxvQ87L2iqQD&HTQ-_65`mBV_wSDYljklxqD!3a;IFpFQXOOi_MPkfLwcJJVyxLBf+^kCfuZyBr& zZ)fRUiEEcMKziz7(9%(!rGEso+m^x0Qm^(Tr7`BXWlJuD{WW;?{oGQnuBUZ-kh0J# zuBTF-CB#Lz zsB1yss16{OPL%L9W?*!%r8WOwuV&xC0HQE)1gK52WpJ4-0Z61TghKRexWRJ#h;`oY z!K0sJgRA_4!Wf?yCm8W_JXLa&$DGR$m@NL5zYnA9*cD3azK)i|T&ImY)_lB~5pYe( zYh1PPlSEyPKw~nw(4#@-hl7*wGHYH!S~x=<{Z;+kHVL?V`)W=cVnRU6|P+xGO;@$Vt0LZgt||qv7j(+Cge|HWl+y z9j1&F42sx)vjEsO^AECgd1d(M!P^ul+BC+^yCM78aiamZWmWAAxG%Rq4wu?}YuNMTb&tRhb`UbhE<>KR)0uY>wm!$moSf4@)VJUua40d2t%AD1(kx8Nc! zq~^k3qD3lH9?oa8;0Z?EPr$`CAxyI(_kW-Y@7jr1S)|>JxDJ*+f<<|V~GkzLj6UvZmV0cZLi~* z@=?&(-@?!GR{}K5wBxa$=R^FWaZ|Z)YAXbXMSZX&2KmQ_(=M9T8@Rv_=Xy4G9Mg9| z(YB*$eFMRDM7eW}?YLoKZOPR-t+sc`bz$waxv^2J${u41eju%$_I+??CjpDFXz`DT z2=3*L{>k9yvCF8P&auoWK5R?m0;d8wAT^^tes`_RW=d@iclf8WBF%QhQcYd$pSBMe zbMbR({r7*{K(Alq_~>NlXlRDE3Pyw0{7fh%{gLj@j|IIa-_&d%8#~JDV&NTAK8N~f#;z)0|`!^Z9i;`oSF7Cxpu7T zB|CVKO^j$=5jCznI*Rr-dox;4;VQE8-S^lnQ2C?i-%~O~g70_e1-K%UKfH-hx^*(N$IllPbBCW%OVm;JZfZo!Z_U_J|#@69% z(vJncK%1Rd@x?Q`8|2fwhBIs#|F@+wU!e&ZSFooK)k%HDwJN+Q6@h#p7l^6l`Mc^v$1s@69*lt>rVH0(FcxkB7- zOyz_bc*H8HpgY8MyxAB^l0jpoduf0XJ8H@PQ3)y8?FYOd^87-GNwTbI2(p!6VS!}d zR_#yBhiC`)(TVejJK=s)qvodU@E?6yq5#t5cu;nm@tvHHZzgEd|F}rdbTZPne<3~> z6UE_MdY|4S*u(f^`st)dHTh1`aes!#N++O{#Uj?GOb?V2_RQU)-HRurEqBz~&!%IP zQ0pY8Ph;%VO8Pawi7p^}@;3qdO}0f4Y5a`~FQ3rm6KRhAnDw=nn1E-gH!K2fOd?54 ziqQsnT+V!=dsS>XS#zhMWX@BuWVTnf=`+91bZqx`9FQOX*<|%K%3Mm%s`Tz_M#k+QYjXS*{&U`7-|2>^ch5-3?7&-Yd*{p%9o1m-mQFo8 zeC&h6Y!#gMBAAX@equzzgTGZgl2vf@;8fa_|4jBdJfkZ*X)6B1bNe@}VJ4YH;L~k!FW^^KoVU#*Gq_rq&|WOuUZ~_zy@@i@X_OyS zQf7mxeqr1V6eea;MV>Mf%&-~SUFxhy2_c!QAK`swlU z?MEVDTIUw}fOG#ZQ)eb<*7=r<#4#Zstxxwew(`vw#VcSC=G(l`GX3=H1oTZ*!0pH! z%(t`DM6Icmh^#8<9#T4AqOVK9`Y@xQw|hBVb}p*Z=qJ(Th|j1IJ1GL`YWtflM`KWD ztNSha2XHWHdu^g$Wy)|M5mT)_ZRF|QRZ)0W2whd7?4j)b*@U1VHzz8q?MjAAhjuw( z(nT1lkvZ;3Zu<1lS6HsK*tM>>jGjV%5J7I7-@Tyvc*7ZDP&nVWU-^mpv~##TgorJp z?^NY47x~j$0^n-d;u z8pU)joQ}^dA|fwMtI|0`^$ron%QX=m8C-#@>Q0Nk2yUnX`}qAaf0;$#I)G(zS3-7N z=;RTsPq`z(25cmzB%Tb}m@&2?OE!gj0)y!`Fn}}}1jeapz9l*d1AET>;SbJxVfNI1 z6bfh2kv}-tIds+DfwM2j2eCgL_(Xe>=fxVS)_?h|zE}Tk!1fgZFx66{vwt#utl}KM z%{A_SJH2}|Q%y#Gt@C0sAvCBoVF+9rews5;bHZVnIH3=fa5>CryyGc%7)WFLYBae9 z1^e_nPSy3?kdsq!mwuK$ zFj(wxF0x&y9+tL68S(g$D8qL&vpno1M*5m6i1~E*(6_2h+9*7EU`!VeeF5T7$rFTT zKW~m_aCb(LgI|4Ov9IC{#PJN`#(`nYX>1_kpsx6qY8o%AOHKy$87wk#x{kAKJmua$0(K94sKqc+T9&RC>B{nq;gukoePmQFE) zYv*ueW&fhVb^oj#YxZg4VI|+FsZ8CcyUm%27{b}r-+Uv8|!an)p zD^Os(+2jFz>9;9e`5j-^)KSC#N*4qJz6#&Se#M*Ao%&SY(cY|K3GqMiePe_#br1DD zL>EV9o`w01B9pKt_~SvREA;J=vId^_;MF3mSdEdGiYhkh0*Q>Y*SYYG!L+yMtFt+0 zjPJ1bu>2L=!|Pqo=)}ZIv-AGhnQcbxn|q~&Pfr%4$?C6}jvS%^(l>v;9JQD&_vy!z z9zzC+GSQNpLST{!sQ-h6eI*{A2Uy$o<(bP*NRZjQeisMAC zMc7LCYF7~h0%?D-X3HAcP9nj}KRU1q=w9EZ{IVI0ST{3zue#l-KWzb`UKD(Bn`1PN z>Ufy5E*KaX`)tV9MJ1)d2S?JE1g8Gw?Pe$t(Jxz;rY`O|F~&1ER1_> z*-M{G(3R9_f~41w-xl^lNAl#dkkB-N@%A%R`Sn?In7^%CwWu8T<1u?>yU!ip@)pIrjn#e^K4@Cy-${9Y$uwp0G6c_g`A4!^8J;7e%5Zh%O*I)|UzIv)V|@L>QesEm&<|Waiyg zszb&FDkh87RRy+J#(kd`al<({&z@Zc@y~yt#SxYUO(E_|bftn>{x-R}a|GeTcd5ym zu_{i)FJtl>?yulrGgV1lz6`RQ=O`tIKct!IX*8|CklBxI7Pr#y_v)3Ou!eWHV>}y) zdYuSw8@W5G)oGR^Yhzba8%cH9A&eXeJG5>$&4-lVT?siik_|Jmu~%Q@v%`Vl*gOh1 zVt%2b4{gLdU#3mcj`H1STM5ai^l-ert|QYAd&JYvfwWz5@7G4&0+~w>%grGRa;e5i zuH_=ua^(y?aHjmrhZf<&v_V&W>EnavHb$ocY5#=|`}y+GN4#3r7GL*A$nml3YT=#w z^4I3*TI;dD6#9#wiLZSw^AcuflxEoG>+@Q$Yb6wFuklWaX2$koT+R+&vK#VTT|4YEj$8DPY=l?I!HMWc zY%!ADQwxD)W{_lM{*I<#iPE*^!ts=F{|v(B%K~_xTxs56cLriSU13 z=<1|}GrRrujg3f~@AH0R=bk4wp4qO0W9HaTE2c}TAir3ib{87-2?xCv(S;GNivg*~g600q_0V%iTZq@-+ZAc7@fd{Y{Bm z5WzTP9!7f&-WgtphpP z3GeM^U;S)pj-^r!#*Q9GonAZmX!=WL+L=zt32mLceq+q(+gqpO!g{p=C$sjS;SGz{E6f$E%p~(YhIaE9t^6E!<0x(BQN^-(p=#(%MknxrEz9mFA2}*jn3FG3 z=@Q=3;u>BXbl4`DZrVVz-*(Gu=}mp95vzVZGRwoZ#gD1A0GgL}f;6o}Ji>O%xb18( zr%k>$cZScC9Q17OVfnbROgIqZ#H8gLC$heqfR61J!Jn0~Ti6oxT%XR8e+D9og5;=) zwcC)No#qRZ&UFwT?~affX#G#_g^Z&Pkrjw>Nz%H~F{5$FKX~@gxPIvWYD6Wke?3}# z9s~{FK4&<|A!$7MF!vCP;TC;DmwFJ>;5&bo@C&6022MbuP)j-(f@c@ zOOC`T>jj(eGq8XchUuFK2tGoBxB>2s2jJ0n8yX1r8Kam4J#kTP z9YVixJcZ1*Wf>7l@0nn6;8UQ>g0F)pY(Vs4rg9Pzj?<*_$B1Q+tFe1cQKoD0hr1*K zBSRf%f$13W@ero3Y1~3jjyoH zbZ6*o{OL?G!D>gd$hC`zYrX#56y#=HPdeqWVfMYaDOlf_P&>vX4HGYzTIn=KRj0(PpYRd$?;v0)fI*RK5W(T{a`c2kB(VaKx;`u1#dCdAkEmSmO3 zT(_x(EHendzU9qe?j1WV6=HZ?!xVSeGY!uI{vXD<3E{0KPmDWPb%agbNk(J^K7QI zDAIF};g;4#$%`Hr_5b4QE#sOD{C?rl9nv8njWmdKsE9Nujl@QabT=bKx;sTWM>mWH z=^WkN-LPl>`<(kc=X{=cyBF|gyMEWV8+N0P#qu!x$WBbV?u51wsgEyJ%92_9%31K! zAv6v6V;2Rb%c)!J99-FTm2uv1%evHld>+&>;)oqDz`hU$Gu>GcGG z6w9iw(9pLX`2gZ-SYXp{;?f$V>L0!5>l*w07%HE39a55#c0#GSUB1^@)0+UnXq@s~ z8X~FM2S%$_0rJ!Mot@O=bcG*;vQ^=evB&ZZOiZ5<5;hGhAsrS*xN^Qi3dygq2rx?u z8fLqZlKN$RAgf?;_puasl+L*ObL7SLzqc(5_F7s6Pwxx!T-Q(aQF1;L8k$vuwnQ?p z06iHZ;N$_I>Z94d2N_Z?bTS92Z$N*rchPJ^GeX{f%V@BdWs_))(DWiBAwHhbVk|2@ zv*lLq%dbQEni1Z6QT8z6T)um%2<~)2yX#>}g4$-6V@`kJm$&n-tpP*nccw?*pN6ys zJK`E@{z#b`tvh^j=!Z`JwPHQL?1w%5X#`EEVf@AP7mh>{G=hu7de?+9=W`sO-ecr` zr9=#Q2c~`IY7E4Q!MV(+{y?Kga zeY7fl>v`7Lmm&vWQ@X9eyrh&Oy(kbi#yj=2b9$kIw7d>)#;9-IQmfZhM0fYbRhgn= z`Y}`06{agox{g-sR)>u@RUxRw1wQy$No$4XKZLM>=nskuI{G+HYq*_3unYPx@Chfq zdIN9Ral9YFPFQ5bdt0W4j|q7ljwn`akuk60dy{PUcD1mQYa3*LO9;t+8f+(W^JQ>5 zz;Fv~W2jt20^QqJ+;Oc`Op-rFBZ26lsPLOigkiq`reFPTW%JkDKI#(_f56opyy}m} z&AwgVrneS|n2zUBkG)@CBkDk1^CwVSIxz!T*ch(e_gsxLV{9R#kB^?@byyrIl8Vcj zjOmwu!c~{=xT|omuyq%p?)XEi^Kotg21__-D=j+TF-Fn(js)#GziZ=#?g-w{^!ISDruw__xkPx zV%kSu$+f@{dxs|fp?^KD3HNra5$?i_IJaY)B?PG;(BQxr)VPFX+^Esi=6ShO$(Y?S z`wByEV}PzlD;5_lD4#8+QVoTw{rt1+8R`+p#)E9H~wgbi}+{3*M2#V}cRV1@b-a*PazpHYW zAHkrQ5cQnrp97l9YHQHlfL6TybPOd^nL_wQW+sHuy%KN|3fYt6zkKwK!}MDJk$yg( zn8k$xUD!}D#Q3pA=J!STi#PVy5f0XjkIZGa)-#U$M4X%v@E8;sJ_rS?Hincq7%~Pz?!y1Rq6B(!lf(Tjl>J6 zvOG*Cd3-0A4{29Xj}|PJo^VMmR8==$Tp*}do;X%dwlqfl5$Ky@Gxf`GcQT`ZtK!hr zIZdz@Xbo$vxU8cq>lRpqIgEP@sJUK=9)B$wtF;C0rY<5N>tVIQay>gQ+^9D96x?Pgmb4CeA9{>J4| zG?Fs}EUMa|YJhE%dRfa=FH5tWWXLcyL4NR~LjcmN>9g|+U}76@X+S4GgTDxZTZUUE zImrXUJss;1W!q(*s=|=*SWQD(9Zo>_ZGEiS;QteP{?E(%()Q|y7qTDWaKOb)2qPwF zU2kvoMSpE(jY6q>1q{)B&02FP7}J=1@A6TaA*)ICDeCofX)q6;ZVck8c6W!!ZA($` z_;Zkn98ds~b~TQ?RozFSMDQbFZ<$-ixnVTFZ5*uoZM~3@T%th$BoFcX+T}ro1SyNH zHsl@{mR%Hf>U`Y6{&z$NM%L?;HgpIEknwx)k})HFa__|=|8j!jx5W&QZyXyJQt=UlCeMWD3NTZkW&Ch<5_?{!Fx;bu$ z+m6fP?7i>5yimJ;BSNb=I)YigHy(+F@T1ilgHLBO-Y17k;9VY_ym0aFRGZyD_7+-2 zCEcgp=@nr5K8daHlf|$||6zt`sq2WRv%h@%zj&H#oA%Kmt@=FM7b&mjz|~WPcRfBu zOkK~>@%MC8&wlz71=p9zgUo!z2N?}sQb+Y#9;MoqvFUcy^!W{oXfIKY za|U(hjvNQzr6So5#g?V`tkd-EUd2w+{)g? zosKj<{YyFBz_tY)??BPn#-!TllYT&1XX6If{zQ5F-Q&6oIesppL2zi^X&3uF4Jx?B z_25T_2@X=4^XaTE(xxzn&3aruzSb)#DXIP0{J+SJ+dDh|Ce1hi6z^ELU5=+e29W#^ z(I(?DK>vmMY}oiUnOkmsdn8REu_PrW$|eyY82$cm)=PX=14U75YUr%jO@G|6`sF55 z4C%7~3kA`Z7R@l>OsVEOXu}*~tE7bU-H+H|vy~I!{t|9bmC550eG(fYp1&C56YNXt z4@A{V&9{iIc%yiwNlYlT(Y%2R&`l0t11MhZ?1dTFyu*PyzO^Rp4)FznumC7H4I?G* zsXNm&?j)rFnx`k3B1#{vFJMo-y~bbpzH=?FmX$8Z&6XQzKK^9q&O|Z^QS~m_(qd;t zmF69~%{JKZ5?A35sn>39rzVga*V!DpA7IN`J3N?2Br9*g6)~>?>OWR3U=CQXAOGqJ zlA)=2+^YPb>Ua1Z>d$oYfX&PKMAX}GK_mKv512;WnhtyS(o z&j1QF&JaSu=wR^Ws*FFXd&j&vrk&~e`evGH_y?mq(kn_^Gl)hEAPM`jzhH?z^pLqpv-G9JVbO%b6eIa;*#Gh@wZow`iHLR9(R(Sm^a)~ ztaLg1v>!^yMUCsch1^rk%9-Yp&s!N_gFbPaY|q+WM{dLsy-A&Y+2=PH6)hXfz6mxX z*{Py=*^_cfEx_Y;5rMfp4o~IUs3mXf|D3pX$*!%qQB8J2>>U{NPg;-1S}N@MeN`>g zEsK0NqLNNME|}WSUvaqhinHs(o_ErI^ATXkWxOuxq> zzi4Tkyej(u2^BK^0B^rQOBE;V$4eJXq$JE`YR7LsQ1IBCNe(`Gch5}CDPY(3oTcP$ z71t_cnY-lPO_+aiBX&ASy~(nrt$k>!d4GCoGVRa|S~qU6W>A;(23FjUfi!p3&~!2| zAPEv@d&zX|$@nx2#qO<72h zujcrgYzLI9;m}TG$rz7c{r1VDnP2;8=eDk^Hq9nm;&JxKSOb+1_Wgqh`G?w;ALmkz z-6IWT{XvQbzRx~4x4^(&KUWzt6E*mFx`G{S9(X$MGLOYkGk{5f%gJ}p7=bcpYC{hq zrtL;W*FYyG>X*vO)Mh8A~y(!*r>x zzWaW$fk6DCMCv@>d!>ju6-u=#os8eS9qv{DDg5-f-~O4a<>~pWteYY|Eln#2yWgab zIoBA?8t0{kQLu{Q5ubFNs}vWg^y_f`Z~EWo{2}cUpKn!_Yx<+#1f?FsjO!2Q@tEBM ze|x1Smcp7*jS>^bg6GR|waUqoh18*cdU{X+%(LVLwuuH%%&S8@KsfR!613ViupdBn zltI`soZ4`e8$mFCOf9#QDbX`p8L{~iZ^BRf6PtzQ?*km7@MPitXRqBiZuywsh4u{Y zP>1T>(&{|Xi#k)gTamm}@Lm({BSaUM1M_vZAI*XXMEhw)cWO)h_2XNhL{WuQs2G9gfz`Q){R_uS1$8rTQ<{Hp=T)c#edn0(X5z1! z3LBnOAu5nk_8rMw=G%Iwf|LXZX`sIuB&Aa|IGDjUw8u<)) z#5>sR*M76E+0XML9+g8k)JvM$?DfTd{OQ)|5F9|#rIHLcN5VH2Bu*}%CAv_ASB8tK zb=**A%iY6k?Rn-pM`VKFWYu<%9|`HUwL)X|5_Ovr%%z-xEvs+XLT?b$FJ`#b43 zM&GZDtJm`v2l#`+L-$_f+PLUR{cA~hfF#{GLrfG!2MN4A&uG*u_n1I&KZZhP7j}xq zRwy>n__ZO{o(R{Nc!4^CiDa9a3`crP;8O$K1t%mSm z|1jo8veKQaNxwV*TwM$j4oX!0ZT!Pl)s6)6_)?ec^rJjaneJqktdkRU<4$NloEv#3 zHkHAW4p{iGS3fDkzP8m-d7zPiPj4DAoCuDq*%AZ@hQ)CVVGM#x{XfpoG1_wDvmgt9 z4c)XOBRb8NPjZ9)xd`A-wX@D=lnBN3_XczI}sRBbb&z@Rzl|5D%H@F1HZ=ptGuMHHOeQ?e1k%wps) zo^3*-Yy7)dL4Q!Qie0#8EQuA30c_r&0f9sNLAvWJ)y2)`cK3X|0v8(YP>dY>YhBxl z!sm6h!-E^$XiG!dz4};zo74`Ygpj6v<#o0f~T%yY9&10N@ zxe-dH%R=7Wdf{WgOHvhguwwm3sgz1^GmR-J3A+bFbGLxXMBhBylxH!u(BYwAO5yb$ ziP$K=)AwY?#aDm=UG2kz+IemlXOZKyz!D!m9+&iClQbyNti@xQq7hKX_630xvuwi^ zlbi2GY$Sm^+Z08f1^F`lHO&d zJ6z6N#LqV7XAmyuHn#(M(xM$T3vpi?I@qR~42aX=cvdHaF(4hOND1xYKI1q=%#w6( z_3o%iuq(vH$D09=GLlu^0W>P8thOA@SYXJV1uJpEDZs z4J*Ed!WgBwfcP64N;G3^JCOnpap+bso2t1h?1t;)gl{_o{+bz}Rjy4d?7%lmd zz^EnKDgRvBDc&W&>OCxqd;aXTf^2Y9t8soDddG097I6wmw@YYXiO^n@5@D99=vXJ4 z|BCxT?&!pZh>Wb@VX52#INxN|&?@23I(~A+(;ml~MY~B7Juo0QUq#6Yz{E6}Y}M2g zNxjtsv&sl@^xd5`vtQrbtrZM1)Sw_En^Hz8@=t#KvhwKnbTw3Id+2Z>fFvC)e&sj0 z-g7p(?1|;ilOJ1D^s^ePO!0g3?Fo;VD*&W{c$2PmI970Za@eqnHhebiADvV^n0j$U z#$*k2zKvT}bG-#uHyeX2e_vwb58nj|XL#XY1Uuj!O*RFh#zg`idp-hSuBY?6BrQch zHS=|+hU~e_lCAwjF{#dz*Z?>SEFk0OUtEZD*G#w+?1Wj_v4o^EU`|4@79xBn%m*1i zJv+OYya^L58PV`_NvhPzf0)I3gT+5}mgaCisfaKg{PiUH@FjAsPTAjnpeQ~jW$)Wv zlZ{xN9cw53$G!N0B%8(X*MARTl^iaIpErf;74cI5Nr6of&}1BDi553B;)v{@*&p6! z4b8!+W=e zLd){c9TT*_4FbJNeFq+tL4p*`Asu~8id^#4?4i|FVd7HvhBj_AcsI-ef^zayS`G5d zgQ$iASYFuMtup$Z^EHO0Zo-V>9*`=F@vwX^IL<|!zf_8HsY|v1t?7MBp4V90NwT{w zm{E>6<|Wd?;NlQrC8ze$`j8M%^_krJdH-LZPM&)v$XUC|jd}q=`glu`22TJ?EUI@k z(}t$k)-0*FSA0i#7V>AMHN6(6p=yiyNDt{ZcOa#n-rtS48@v!yjkDweRlx*5Z2!1S z)Y*vJTls(M0cDh^kZE+kVAjhict-pjB?eB<8^95@@)w~5XoU**$jh_LjK_i;mhlzsfY(JU&2i zQU(=L>q!bAyBm52KgXvdf%tZ^W;)8FKD(9#5$Wr%!L#00Iog`EUNjX+;iHqWvG{kI zJ?f3_UO!#?JQ22Nrz?K&(4YDkH73OzVoo<$>Dmb+MNtHL3m`w=vY>>6OAndPN|GaA zO!E~MlHC+Wzl}*k)pZD;^tw*glBZu-Q;XwXG|v&st94Y??0-r^r=u%km!`aM$1&!# zt7m;!DZ#B<)2&>!xj~Z68oeO{ehCfD9ODu3YLpei6gm(eNBl|@KeXN6t{$NepXkz9 z>&NBt6YCtCO`jy%Aynk$oY+bXLsVK0ufZrcnXv|xeO0cR@3Kd9k-NFo6! z+*+6q*-#VQ6BGnAdvo{LbB=mXT2kESi5$o?vlt@o`$vSB3ePO!B+~;1p-x6{rdSov zT30Vi8}-M2IyUu4iIJJPv-y+jB%V;R*Ix;Q*!Gd4qu{*rR(+iqrn+>@#=-eY%DmO| zy)8CrdXVpJQ_$0cfzg4A*&yQ=`R|nl=depxN@>XxVUJcR$|0^!3+9HLBlz0m3+78=bXeE!!9QOqqdM^XE9v3MF6 zE}#E1N!TLqVvsKT)2C+FeO$qCOw)N&EEbAvv5-o>+^5@Bcw9F4dE{&J066kk5Y2Fo zgj!YCwgH2Vf_Y5B%105k3NY?W zCVph=PXlXA^EDQccP}@O*%w2VS&p&GRk_md9y8`z^D*w%Sn|5s?vXyiHM1q(0BcFgW`L%IStrc4!OG6KD?U5pNBlP7Ew*)!fS7}mFty*ToxE7Jyc z06hnR(PHLrOEB5clYZgxI?Uk%a42+UZP@tvO^xUqLvwWD1z&q4lV;z6tk z`bH!b6zIk<^b<_9w&T;kU@E`1>vX}=^9&zT;9GQ*a9_OQYVNyi_CyZ(%bk&Fa(}1e zCSeQPPLJhl@+bol*_%Wyzy$wSU11)Gsti`YIkLwm=s&am7l?&w8S;Bl%`v_0OtIYK z7{WTKm{`{LcsbChQrLrerWOFSKxps zEj>gFIaZB}^y8q4sr%shD$8cG6U8l#{#(GTTlAFOV|Enrr)p~VW z+)EdsG!C)4^cQ7Pz3NK`^&qTj1by%I*BE)IzWl(aot7+(%!eEMDp|_gm5-Hh zHc8eErsHEVd+QyAf$phZ*FMUiWWBcByfzoHg>SCy1UD*_kq z8_cm}&Xqy4bXS!~jQ8f1sW&i1M{F!_=br~Q?tateX4n-(py)+q!vRos|9Dq$+}SUq z4L$r1Do=__iA=hKjbxp5N=pT(A}ynrR(|46%!UZQ8ChqKaiim8kP9CWPQcP3v&2j@F-r=O=>doiZ^9jlqjQC+2F zpXuurCVm2y(vhI+O@SaFUlus8RqE>zR)5CRRk4Qlr<2V~Rug?yU%cCCVGMmX2ZW03 ziy%a0P;}NP{H0L|&uJNN_sr!Vuaa=KZL1b_mm$>}H{CZu;y5|I!;QK9y}4ADbVP4f zKgUzTxKrn>XnfBNZZ1DElMC_bE1b5}yD+g8Qly zI75eOZpjaxqOy|~klL$-3#z{x93=UpDJfClum*COBkSl4Uwqf_p!{`6EC{xs$K~7+ z6*WL$Ia?znet=(+?>6#`4|zZE-<`Vr#d<19`A@F$|FWK*Nzou}O7N^G%ATh--EJAT zNsVHFC}UxaS$9|Acv)I0vx+5+-z{hkQj(P}`-!oKFwy_~peeA#A@>P;6)Z|(BWvKl zTmFs*t_s_Z%N=t0-XQ%*BDpl({#AR?Ld3@;Yu3!5pibFuipMCh;(p1q!s9o^pJBbrkiR};dwviagJ{KN$>)57+1+T%qzU|B z%NOYG?pge`u4=fUMMqs0H_Rc|=AepB|3a4UF!izM8kej4M1U7kB=!#>*huM5{_8cM zBDMqw6bsfhYU0dv=%8r*QPBs+r2dxQ`Swoifql;Q|ZhQZ2rR|g!6@b%`b+-t_ zX?qA4U<0G`$Ied_>_R=OKeqeD>*UhxuZ1g))`RV334jb+>S8S-Yxf920 zp5Ym5tEdvIaEtH4?$$sgbYn7DtQ&s1lDAZNsxaQwu~bYpph}z74-H`bRHki9#d4>g zJ6Y(adjBvqrn#h=Axv+x;GzX2xJ_z7yhTz7q=-ihimp@xXIQ57(h=`;TE5F@A%-242S2wV>v6}R&@@^Zp=3TmS=&enp zSY#z&$Zm3s@10zba%`s^+HsCMIC;DL2`dcGNvjz?2Ol!@HvqF&F7~IR`E(b7%3JM^ zD~|@%_j@l*dM{7iZj)6gtk~hLcdObYV&moAwq$Nc@BcHExu31_?ZHANI|(5b+gmh$ z@O?R7$BrP-oqtIDgmjIQbPg@@+P>e-`ZkPDEo7JEiy}d-y#l_qX)+pc`8Srj>di_Z z@$k9W=Vd$OG#`c4TzVx#7^|Z}(Iy`K%GG=!-4%TQ>LuW~bI~>N<6(6FE5!2>&v@E& zpwWE{fLNRQqS)p+@uQo?5`g(sQ?_Q>Gzu{I6?9e?XW)9g!V!W`_p$kEvdxM$!oZsb zv1J92$86>N9Dsm9)3jN}rii&-0Ow2Cyo~Ak2IA55{k@eOBf!U|p zk#EgVnw*A)rsnC~`DXP9&XFqZd)$1Eh1$5^XZCeAZl^1S6b=KQ5dHQJ$=2UcLu(sf zJ9LF|FmfpRyGhuTmR*zhp|$h9V9BFG+{xh8H$&CYJTVB{7EGxXZcvv5Nb2gRLDum^ zd}0zsL)^5>t#d#m?Dn=t@Hw=Uxlmcc#b&1iQNiNN+izu?4|gjv6)K6sqHGj;G0I2v z?wHI!z9Rnv%lnnqxDM|n8Z6iRR_!G~442VkUfc9QJ1}i1=b?NyP`~@Naj8G0igA|)>X+<-oBJ$ zue2Myo5U}-v&oKpMnBP`X=?u5`qr<8<};S4lJY{PHCR-+#5fSi3Fj1oaQwtCe~o*1 zhB17qkucmPT_q690TLO~WOZb(+?P!#wI10GR4EejW?m-Tf)$J%Q)s}cZkD$^WSdKnV~I6cG2vt%@} z63kVF&@tz=B?uJ7l34WmPve%9RALozqAzTGH$Am~nUV%g1N=D8OAS}Ew+}CthWm2J=TY*gw=Vo>GSA-&S zT+-hiJE)%?rz<#X4wL!)JEDenDw}j4*@%_jkf4Ez2>>`(%Y2Xs6uICJ8@B+qR7_B) zE+(ic7@#NTfW&DocHJp?DYEgE*pKRl2}#;8eVLV+wbIVqfWzj$P>4Ug4l~Bx&$`zt zSMvNPjA!=I1fjPHQFNbg23NGt&G4|fvzUlndN{7dnR#Ze5nT52OmS|i!OSEM95T(s zOZS-L9<28@RFiAC7lpD7T^@T-#w*Ac3TYR2q6 z!xrCR`C#j8MeM^LUeoK*uDZ#`>Z-|%#s3h-%$6Nb>+A=_A!{OGCuM2Q=zFUV^AMFo zxKEQD27kFgQp_=G|2DT9%Etbc-a-5+Lbe6L!vpb!LcB0r?Zw%TCaEe`1_r>&!w3Cp z8e0mQ4+j_h-kCdU4bs%2Bg{i==G3CfQf$pphOnE)>0=I=r$15Lg+8;}stuQD2yu(i zFXUpSt@9l^*(u`*0k+_Pt(x%t2-&B4(RrOgeAxi zkxXAy@~)fJ)J`ZOS#g?-hXxV`z6phK)$9!tI8>@89W7jgM!D%bM&icpBwhG3)$5uw z(uGNT`xuK9ZdcyaComYk-UwbywUi2@i7$Y*aIF&q6a18|GLFdVHvkZ5VUCOwf*3F4 zy$=5_c(_=ZPu=dP;^A|Y&cAPf612`$IEq4l!6rn(hQ~!k0C8qnzqRrSvL*se|aVeD`XVM`y;w$ooE5swLr3_ta1Vz;KUB%!e{<`mg0nR9wf- z@bw%)%|h zIRS6G5!s8IK6j7Zw!wnQ@Z_y_-iMdR1Qb&UrQ;@VbcTo1krn^bjb7pj9e6bMm0RRh zk)e?SM>3aMzrbySMPDo1lw`VLN^`$iX%bgb^Tfo@*B<7>I4gB}N1jW3 zir-{D@IeHAe_Isd#s?%_Q-?(;N%PXrR2V2m%D;VET>ToC&hZbmpYC1tB_ z@XnMH=d9neMgLc?`k&jv<(QPs|G5&?nd3P1&rOD zSxpNQ@EEkKr3u)wC30x0)h{ENTr{YY9VRkxD1?)Z@X6z>k@5!EAd)dED5mQA^zO{f zt~8&qfws}%$u87_o~F6~Nn9XiPd`VkWldo(ZGP(&XU1sM0v3_{b^MPWh{D3FG8Y*h z9*@1gJtL@J@0ggEpHB{%COP_u+DNG3`P3sn-|Qocl$pz~uxV#hkB6SL!~PN~zanOi zZ8gPy$%*{z>DJrWeX6?AP8Fd}i=qR0uWK>-q!{ndTnfe+d_AEa2{%>3qwv!5z?7(7Fn+se#fQH9@bFE7equ|6DpP^;E9>S; zd)#v1QC`X#gd`_@kQuOimb-u3q-MFv^=os6#q;d>mOtqqe zsvPJ72?w-ZV|A3ZPPf;Kvgb@H?ODo-tHLm8#w4iF?k*xv}{&H?Q7i^i@KfD_4 z|GhZa+lx|N62|=Wmr}=_MuzSZMdwGou_Es>NU!+E+F0t$uIcI(N^rd#K#_(Y0=1pY zVw!)sIr((0t3&;Wg``>*kIp-_lUz@(TUbUq0416Wxg7zOvN5BC1C_M>Bv!f+uWvpa zvi#-}obxSY3C%d|5Ng~O*SWfFbNPodSw+N%+K?R9-hIr1jgzrC!cA=MI_r) z)ucFEb~W-Ndva40h(;{_om~eLhhFqHO{=B0wi*9!)h}-qO%mDAC-%~+&m(W`FlIF6 z@Mu;L=?RU^-Q&Yk#J6FelKYHtCr{X?{F8QIIM(_7&OC|9aPqF2hRqATpBWZ~j*g3^ zLcx;nIHDb-_7fzc(iX6^ilNhw>udC^z5d91<*!DCfVfk;!F;iD6L#tPHSh>)B_|r3 z1HJ!2)A_>_G0(cgUQ=s(-FJuedD{~*yU*KxTkJ&z4f>tfKe=NM_eHbvaYu&Rn+zrg zi7Tgqr~mBnKQqKC(mlCf+uLttX>ta zqgvQxno8DIVe<|M+g2+~Ri$~EYrpx3;6S@v41QshN8O~F1Dz?8N$M*P(~=i>4t^LI zjEb{PV5_9wYZd*aF;44qX1vb?HO+oh%WqPdXf7KYon(>0_;gs6Vd>OAVmUi;Y(+h7 z5z{!zA9kZ&dB{BE{8-j6;Lp(P!+md(RWIMNpvpwkj`;T`US-{`&a^{y_{k(mmImeh zo;!{P(Vj||C7O?2qKHB}8b7q(Vk_R2Hy59&81CJrIu4KtbiOo}b^QMUxXIsso?m~9 zJ01gYuumD&^PG%*bz`BC8oJ9p-JCj1z5+^#Tz2ACg(S$f8+7$c@gV78!-X zBrsf&k#ugk>&bMf*BkhL@%vlc>@NHD6SMmSkjOO@S%qX%&h6~CXR5OKILJzTG6gDTgK%Lb~c-TjdAiA zP8h=4N`Zj_y$JoeK)pDkNtYtKn#^PH=K64^JI%n**QTsh>YmZx&atsrP&Y}V z(RKH$^!bRC(s>(jx5tP>&XvTP%{}is+oDZy@4Y~Rg^8P>T3NZE}H!l#jj)fQ9YKcn@^R?PhTYR7gkyf*oyCXkK&%&3_%ujDXX@fc1? zxj(rP7DYjq!TPqbWY^MAS*i79Z0%zT;~py*dAP=6%uu!TA5FJiyn|h9$(6?uaOEF} zU@9)*P>;rJ)4t)?38klJ|6utIh--h)#mY9Qs^k000O8S*}+XGw>S| zKf`fnSa%*`>Eu7)kbN}QUQX2@ThOrabW!g7u)S8 zs#K#Atzz8qY-N9COjPzzwli!>83>m!y4?!$*}v3{K_c?u|WJe{>3|Kjy;198GIKt|69b#z+fqNjK& z4tGbzP7z;6X_AgIukQ^q^a=c(5owjgw?pqW-OhfojwR-3TZEt1GooEDZQnh}?UWlZ zmukNg*kJSp1fzOaf3P0hKlw?*A+?JQDG=wQaN))CI+aJmW=}$5<2b{nFt>gIl??og z&5`d2KW(1dNIRDU-s3>=dfn(KO!^Ws`1<~$hkxA=Ht>?eqyORWg?t;*EkzS+;-rck z^A!=NAb>FSdGSMfMupi(^|WIi7;_!6m3ByD8%NHo5p&yvBOA`tW4$0yaX2;r`dTTr zd=ooMTD;+xPQW*ohrR`(c_QK>hjfw-33>csai&x(-Cn-U*b}p8p@fU;E)95t>KwB? z;7lKP0+;h=_xf0KzfcS6D+lT?*A*pC+ggiKmyitogO_F*BpryV{gd)S`q3*C#mxym zqLmL2|MbVMh6=Pu*O&wTtS%VaUeP*|@}Z9L~g zzG>_?SMv_xIr&`emb_F^?yZSM6S>>l`o7Ldago_;Gdk}4&`fC@h0Rxd*Y{(lZ zqnq5Q{|wsoKVH_H=W?R)Q_30N(T}_kB|1Y>tIqC%->L?Fi|gRomHar#%N2%0eca%$ zOIFsl!+fN0!qrz8o2CxcyRe0OpA&6vImseQ?sncjujuH}f`513xUBbw?#(aK%W{^a z!vxsB^}%ZyWr`!tx|)0tLTJDZoZfFc=JHw`iPP>&unDYYXltsNpFSI08Q{M?`x|tW zSg(eN{H!hf(qtlfqa^y$H)xuQJWKxHiHHtbB;TSK*sfKpxLwO~Xv^L2SFVKyU(6UvJ!2X)$U%EEu~D8w2u+1Ux@E=|0&pVrIj~37nW+C)fC}TEA91t%zN{% z%_VjO>$d~GXhp=WdYXtjC+cJ~5xHjLgt??3e4d(%CQUc~mM_kf$JOBPA&ND4Wugl( z(Pp0ttBLlX;FQX#<}AZPaI?=&6G@FjGPXzRk)L3}wX?K-A7%n9>Vqf@QYNN>)vm3{2ZztM$lH;at8 z))EZE5UIt9W8U&dX_|-58(mx55X=8^h|ZZA7^pV%i(?~kK52j``5^9el-gP-^d_Lt z|Bi3|&+dZ%)>Qu!O}uOPoO68Ma&GUBo3Gw>P~8b-FvNh=s=r(Wl4QHjtj19&wr?WQ z6XURU-P1_0tyfCCl^hJMP+qrM3XN`kL&>%HaTWhp!VE~^zEW{HuZ1=tf)=Gp^9Xy5 z2q{O=DDG@-C~kfO`x=!MG=z>tCse?Djchj9jRe|{lov?Ze^vWqlz9kxak5CfRX`oW z4)1u`(et>QV8yx0uccf;|K$C$PeR`qluNf!-VghSrE!LigGI@2=zc;;=>f}(Lf2Xg z-;lO#&DV)H#R*?T91cJEE1QIWIi;0oer7&K2i!vxAsm+*Iax}^K)nv5c-V%0mPiP2 zkw@~Z$fY!is0HrV)8F561+-Y(R0*sv-Ea4nl2N&(cqBFuqrn9(4F z_Kw>hOr)mTlT4+k$15w9p0}jmBfVp0ma*;Fw57LFur%9=*q>~%ATay&=+j>zu?_VP zL>vB(Sv3{?4cRudQ+l#pUFiLKj$dwggd4Bq(h&t+d-vU05KeiV**V%Y!RlB7VzBrv zN=B^@#@yGP5#U~I=g`@ExXk4)MYB7<)ZGGo^-q^|PF*fNeQs1C2Y!L=`gOO#jE-GO zK_#%)^-%@jEqF{1^v@;Jd%t>3B4OwCaV4rKP^_i_D2aq3OC-QOW24CN^A z|Lj|PXO!t_3m<+l?Zvc2xa*0IF2%5s3VHy9It{iq`Duxn<)e5RDZqp~Bnahe5>ENS zK{O4#oY0PctA0)+^9;}m)G+7crA}dqb!!`dGWJQgM6+vWh6HUqI^h)QA}Lbv@d8!O z7-D4;jigw!rr@GCa~YZD!xxVTA?;dQ|4nM(=uVK0U$&6V3cJN9ndDo^j`Dwr4EZun ze%b)SVI(nFAD5m2+6x{I&ij;FLN2iiFsuR??PT%k#XNI%2&HinANDGPq~B^JGQIu{ zch>b^nadruCIzMvO5y{@3GQ10!*KggX@!#|W;n$fvGKI~4FlDrra*a)ubF;-hSE{q zAZONI3EW%UmmrG z>l1T?0CiGQM=fpw+MiAB4vj;YTL^Jyt8Az<3Xu$TeV1lo%K@QzbG&3X##sAz+Sh*bt3l-UD6Q* zqX%;X4g!R->NLd5i`q5w$#evG%St!*&Q$xSt3H_Hna3tF8+qmSENQA5blB@vu3@DKoI&T<&`%bTPVfVHcu+%$vRXk>Oh9?fYvxxaak5Rxg;B6*W>{yoBo;V z{mn?GGD#!@K{F|l`n9_FQqPr9M!)>tQsI#8%nq2uJ{9!Snr*x+l|oa>*XKKOt&J?x`ERHwitd{ip8(;sV3Q6}w!&mDR|7SO%jtHEKjQF$ z_?@H&0i5l4UJBze4SbED0I+#Uo{!LX$D2ydy7+~PNLYTVW!%d$ieVMC^HBc=`IL;o z?)j>WlyV=BbJJ)JLA!9~#EA<-&lT6MYkdNm{-zQeTN7Wh9HSg$ z?{lfY5eE1r7M3Q(zakCf>x|JZy_0i6w0Md+t5l2ddVMsPl~u3;=m-Zo47}6;ASA68 zChySw^25U5lhe4okRFk`6AQ<<*bq+g6IAHWhK`ZGY|I@$IsV4H1Ig1xhv& zOW_f&i$5K;KD4fHi}F~d^uJ?*HBF1^7w++A9og?VtuZ@GaHm!d>8h@NosvXojmNy% z2*Ky_MOW3pF!dtVndsoq^#}0rBlE(vYh&KmWI-2rO6B5b1OPQ{pWSYr{o{jusE+t# z;@D}>F>@@xqHw4-`~K3h^6La%i@I@>;HOO`r@>z%mWXcmPEpQXVl&sYF7f50dHkVT zA8tyv*%|-Oliw;XYolgi*Dkwt2*$W`(&jL~URq+Os{JO^jHJ!<`=hegf4X_TM+@qV zira*%9?X+h9MTPqxHeWC+7};JRoo~h*F;zvWbap-AYuUI!^BX2Wv;gC5CECv%-IdO zdE0ijS^xijVE?Nv=>Pse|2O7YxPW);@iB%cVga_R8|CyJq_+3D6{+$3#3>-IN3_A% zOhjm%xatw3=)hFH`0QcIxI0LQwNtS*&x%1}*yASr_|8ZwO9x<(B5Z3Qg?| zLthM4!?Qg!m%%WihnWOq*JIzipT{waOfKVue_515qB+v4dIyEd5YUBEXDt)K@(OkQ zlL1x+U9sT5MP1?%H^yesZEuE%2X7}sRpWUBS?A$qpLq(f@EfBPx)(whk62=E zz6yMkHCEtL#!}$uHTtq{(ev;zxw&^xoDL`k;DnK_M$c)aeLdf%k0%;BtXEIk&W&apfQmxAq7<^#=gGs^G|kR# zhw3i@^Q%61=zgPf>~F)YbYOmELyv2`Waum3;m6W$Ga36>m z`Y!*TivM!55sY-a7vdGz`rfE4&}cVb+c0D~T6uPqwa$S5*jpU!rCsYaczID`H6W3_ z6q67-3Hcb22B5-#bS=14^rM6I8>TCP+COKCkhCEUi;m2a^zyUit8A#xO+<7`dzPy= z*jOmkIEPyxqVdt?mhHRHc(fZ2gO2Zs?2{1sXQU}43bx6qd)vF#E9m*bnAN-54&P0( z-T;U8T95)F1yU!ARLT1pk!{>@%syQq9e!;J>U6p6VpfDgyI{U(!DakLe~e0=^R_hJ z5{zT)eDAK<#YLd-h6Fi%*&ly^mX^f;!?Iaj8E&k;AG1gN?{(Q3-%&$jN8(~qbWGcF zNfrQCx>d$#q@}gf0)9GzYt4bDy*Svq4Bs1C^#cN>r`?nOFV4O)D9(1R78-X5?h+sb3-0dj5FCQLyQgsr(zs23XYSOTx#v5l>dvqJ(N^`m&$hMK zUK@UL(8*s~5GQaAl_aR@L=f8cr=0E*YLWCHbtK#Ky_ea{NJ| zxta|it4qxMX)=6`@Ldf{S0c-38M8r}%b$6)r(SEV9kxQRpf_VE;G6HCtiyMzT0!^- z=%Pa2O(_7%39ImcKK)`Aci&EfH8$bf&ku0{eG&k<8%0c!y;1s0yuE1r_vFisxE$|P z9C#hvusOKi>$T+W4+mQUu;bP$!c3lvDn5SlP7qXDAl!`1zJco<5ZDpd>c zu7TX1zkF#&9MuY0B4+8AxlLbdFENQY29N6aH~SO6e0!-n(jy%o89SX6<)9$>iV5*E zE=3f%saRCxL(poi3^%@QSs74y5W-hw#tY;!w)>uba*LkTX(mXEg3}&xu^S+ z0^&C9CzDgwZL{&`->!U$zi*mTS@^}bXpEMIOOs1Gk@4}*$5^K+-Wwys%{$0o)xgev z)_~k932X;gRC&>LrwM?uG4kDAdx&9iRlP@D@WqS+DrV_r$YA1v+sDHg?}<3s;|7%} z*bsjUqQE6B45kPosyz);Ffwvvm&#_QTs2G;T9JJG_4A4C?nN)r#s^#^*H6GvJxig3 zU~X6)2OH;E!|?B8?bWn;Dr!+bP}R1TMiwHr;SyM1(zTJIn1f?|QF+bmlcl_XkwR)F z({Im8P=*vJ7+C3pH-Q6ZCodNdt@@Jy8_5he?MbMu^&&rBe(cT6%+``@`E7 zOPmsG*@*4XW-s*MPI?w^|K|VU<#jrx5PRQ8&U^O;gYI0)TuS2=EWB?fOCM!rD8$qh z#p=VW?vnKyLG8~H!0H?MT zMjULY)?914qy1m=mQAR|9xMCtO&fBgf1=y%n~HDu5UL~mJB0ZhCifTvj@oi&hmsts5fdUdbME8&(QBf^KN$cQe#1mbA@k&o#bhKetQJo z=WG(Sq}*|%{Yi3)b5{Logl#|H-N2}^I%m>33WYEQ@)Dl)Za!pL@A1sUE(Pn}o5jz9 zha)lRBrY^{+V6%+G}b=TyPvY+UYnj9Zj%5KyWM4tle%C?SIVoiQChmcmOcyKSHlr# zHF^i@32YatdMsAi1FyIp2I8s(t^exYiUlE;+9&ys%_ zJ)!wrp}R^ehIGQ#oUDoqkW-L1G3caY#XNK@WEV@0JE`obba&j3KA9&lOfNiJR9-=n zQ-pTDT8YeUO4AWb3B(YansbGi9A%mLnb%q-b$0WLUB@b&n5Ao9#b~qnT8rYG# z)`4S%mn1xIfcYJzmCKBMSsQ-HJqiX{viOFl=4CG4ktqG1ZkNs?)^Lr{oxVMYyz(Iu zgC^8kHrJnjvjm?*Hv1~fkSQ}J2&pW#woBAxH|BuLPp4^BT@I5fOK*d^bnQFCWls8O zZaaKDM^2j7-y-H#H!Ln{9q>3*OAipQTwdRbrkO2Oy9Un|`}&rf5~rA0N%5Q|%akZ) zEPp$nzzstyItG)_rTPlGkkA3EKG|>~hC4hS_=o+We!()_z(7@Jp$XCtTyZQz?^?O7 zsT%sWV*knWv5wWXli8q6QbCoTjrr|c@k7WW5&yQ1{P3dhwktKGxcxo!6qghbk=9v*PyW(#F6}9Rxq7705nku#HgHGNS68np*syHf_R4r8Ea4={6yA~1;WX=;ZMo;mnDQ+v_av1u~u31`CZt?uSS*OkM?^>78$?aeOTCx1uI)u!++?azn9ML5>6k%+vJ>Z zNMQOP8%Z)pi!Ev?Yb8q}ih8ta2QG;J6I}yzVRM@L>@q&O@@x&bXNu}H8Arpy(rnyk zr9WW*mP18_{Da^K5rbUB*Y`I+Se`0~IGR|F#pW;d!0%5e5QN?@06Fs>nPZrW<@;-* zzjm#fqhY>wA{$s0a&pvrWOvJvh6GLR-*q-OyhH1z;uA{y-fo;sLa)x)p+&)FP20s_ zwDx;bCAlkXwAE8aBWvVMcF05LMA(<#tvf&9EpN#Lsjr>HVo5)VIkkXd(vek$Nqla! z3Ezp~`Mz(#NH?6$LJBvn(>ZjnrY(R=ua)(_0mSX?1bBxI2Dd-fc%{0@q*-Z;bUN|;<(2WMYigd6-|q%F#sQmSig*FmDf4*rdo^tMBe zD>+L=O&{+iYaahhpvmBqjMtSEq#0qA(kuK#E4>yxYiwI5isr~Z3_!g-1lIJmX2r|< zec7^qrdZBc5fkdF}(P zyj)R56NBESh6Yvi0=yVHi6xF-x<3WJc6hB(hg-W1mDSUww5>OnJXuVSi;b(?Gj0CE zo$^tqd7NF<)7pdlKx?8tDcW4Cuu z-9O-?Ooy?qTp!rziXw@~H*m0{l-XmWvksWpql5n2rkpJ#CPQ&cCn7Qw^>8lC(E$K@T(} z)bYV-;#5;b`GMG`R3h-5?1j_ZbLhF(I${ld)_ibOfzp*(^#gYZE`(3)w5DRXQUVT5 zYWXw4yVW9>c+On~XUhc@;KDaCBgXS+uSyuSE#u&zE6KuLr$6d zK2{iVihju1P1y4ma67cZUjwLRl^c&AJJ7DB7Ses&MW#v!h_(ilS|G7~Yf&9=O+)V* z5(e*AC(OD}?~3_vG?CU~D%yQQ`g#tZ|y4fIg2bexQW6IM8Jb zkofA`#_D}S{;T9k-h)^`h6kY51|`{y-k(t#&a5P&Hssp`#v*29wTTV3abMd-FT44f zZ3(>br^bK8^{!4{_><_30_1^DbA_G_geMk+ke6UzKO6XJ>>7SD5#i*mH*iWCdKXe+ ztRAnnqQ!+^gR@`hTs)Xeg`V9x#@NJcvsvy4#PJ@<0DtkPa3oCnE zb}#o-i?x!I1%63cesgg~*p;%B-aGOfoe|6CY(Z$zUpDD*)pH}!9!{*xvsKQrT*F+U z{~_U~ykbhh!?obj+>B9C^i&kp7@3cILg=zc_n}C;&}TCtwHY`I&O9x1q%~j6rdZ)v z*yH!ZUyEWf7hcK7U|}4cVW;#D*6cpqVM$t#trcHQNYJ;xTB!y9hjAqqNtmwk^KI#K zdvBBsUFQqmM%fy}J3l#yiRXfFtTSQP8*iDCuhCX#`@!}_P&NEr@P*`l`2p_5k(+GU zq)2g^=h*vLr<3;~Xsc9;^1;q@kWaN%g|Fsqbmr zr^wLKTrJ_WcmuxlEGOVd+TnwRvAY_?}(jq zVZVI<6wm+&=4Z~iZ?c%tYz0>*P+#9W@%LlN;ym%hkH65CiLW6imB{SweL*i|`hA=6 zbn@DA8Oj0Hf&Qe;W`GQ0th%E?oUWecDC}>Csav^(^Ons#E&P zEMm4)>rw_iHIGQ!ef%~39u7bCV(S4{zbI;51-&%wx8L@nN?&ok)m&<*<$T-I<)4@3u7wTncM}mFHG?Nti_}=%rwCC)KU+FlcNRE5-!$i*2tV&jTufRl zVsO#j5mcKWiVSR|P%OVU8W=vaLWDK*Vfcom(lw5OpM&2BYw7C+ktHHR#dO{RQS3~` zeEP`>?HRh{bVKb(2`j%{-hgZTGJKAR!igq7L`a_j;Qa+>j`JTWfSf-+9!#%)=?frS zh_J{H2+$gg|8-L~ZVUid|H*wpCu~KjK5LtXb<)qfx9JQ@OAsjRSarlhkR~c;boACo z0ZhsFS*W5brE}I98BTRl07)1ZE@OFb^N6?i0)7-Ngei=(P^ju9eXs$0lLKCDRR%`? z$mb(c7_83yVDAV1o%>n)Mns5OAMV`Ujw#CdU{NekJWyQ(dOa~b9$zq`L2#H=1{(Y^ zjZB&71Q27#Y@7cw_u}mDFdq~g9YN5SFiyTA$JQmV%<(W``;67KuoT?O=_e3L(hqo4 ztDAfh@gpaHq5Y;Hg}f)HDk4<2kCGw$`TAtCmV-Xps{|n6%fn8kJ1flVDkvTZ8U9UP{1O;2J{>ux- zE_F2p)pJDniA^kG`*Yqc*?Y3C{Zb{9oFSq);DAzPe9m@RI2IQ=lkE9a5fdkUoyANwuduI z9^kys9#PkK{|Ex| zODlza%^p}j<@1!hb&WAT{vN!D8&@n7QS;fDi(LWC(^t&ikFWNrx`1RxJ)*rAv-l&< z2TAPs^^xnfyYWBcnOi3ubx7+hXC9bs?I-mQezv<~LVu2Zs#S~JIo#p>tZ%Hh!#JyZ`iu)7m{p2<$Xk`t%=crtuL{bZ{- z280n0qgr#9E|oNFVh@`r<~Fl+m$}^gu$%LBy_$bodoijrzl)5R}Q#e8wLECbVa&A zz`!SwKl569%)0>!OsNtbooJd4LY+d9uhc`xaT|7Bq`Pn&5QQ^Q>*xQp?eE-^y5)W? zyjG?0561fR=x=K1#MsP!F@^SfH#poIo13Dda0O(>qjq~sBTXrP2+{nmnP#a!yTwWD zoW0^qH9+K9JwfPtDOVP-nG?;l;h3{g*cGV= zEsVy*&p+8m_&f*LD2eDrP!9irYQTN|D0|y%&|1#EJXVWpRd5Y z%@gc0oxlelYj!*rk6V-vOc&nep0*g6?D zDabayO5Zz7@Z4l%9GxS$E$^Wvs6&N3^=e-CVy|H`K6M_b*l+zm_=udxPYkR3K)mD_$;@x|9UG4-#o{-M(OI9R z>Z0q^0V9YBW2i;QF2&HsL?w}XSTTA=6cjA;RZL#wXdiR!BG!!%Ds++WL*wuk_TQ4DA__b0@Dg{ z+cn5|jr|yBDGiRPcuvNMQ|HWlW_}He0Y;ulx^Rofg|$DP(HN0DTj&z%Ii6sN*}Gh_ zzN?x9#AvG4Mm~rGj(SilS;?Ivy-` z(`LoF0}}>6e%Q^ZpsMZuky2W9nkKlGG<8QG$KAc)wl|Kx&{Q$Cq5Wh!^{eq-K%VpV zM?2kd;Wug=izCmaBH5Nd#}v+k@Qeu6ob(CxkSlBo zK!1RjH1$|M8wP-_t_r1CLA8o5ypHA-{Z6vB!ixGR98> zf13Ip`920#9pLesQbXtXv|``;?@YsP`mRT@y7TivK#O(YvXP2M6mm~?9s8?iT!*}` ztSw}GLNAj;z}fk{_@~$tvaUe6;8ub`3Pa%AKB4ckWBKa#Zrv@)wh&|1c_q3>ZKqwyeDy=l@JTjjX1d$QrIyXyvZ zJ8(W9->rR~{_N1YxqYnLXpfxeyh|(uGJK&R*0LhW3V;_l&h4J|U>%c1o^6QFXYxsV1f!2(O7~9^Vh!0!j&jS6u2DM$iOWN$ z?9EJg8q;>>TmhAw%ohdgx6~fs8;WW6B%!Rya+XgQO$`MXRSl-KHN-6E9kcCQr9YKU`o0n*j=$d2tf%WNg{(VCI*65_J-L|*9GlZ=C9Ln{H{PU-t>in z46-WX-4KFZCW`G^F>#doO)eVBecHa;ff3N)uVK1MHwG6cL^3$(P4HJyt)`00NCCCs z;ub*S&nr-a^;x1&)S z2%SSS_8^7|;L3imO}enNvB+T>Xhv9zTzh4cN1$+Ixe#leA#3QDecIBVG~eM_kGYA< zy8~&FbM)P+p-KA=W$_4NLv?AQh-dZy3&S4%;Zc9$pitp2uc&A9dU^3oq_cxCI0h`z z1fL2gY?e$I4}yLaU=U|L)rPS=vI#_7p2U%xTpt8Q#|qz0Nw4)=%-9Q{kVkwNC?N$x z&PY>OWCP_!&2M8kfq55a(;z{TL-W@hoe^2DnFVv~V7iusUxApvm58|w+G$N^Gk%_I z|4Rh^M_Be|#<8eC@uar|pl`I&3tg+1|2!>*V+IYGsMO3tkEywZJmpjgyZ2b0K3+J> zS#17lRJJYB&o6WnDLKfsr(57z*{PgHl9CgSPv_Qc^0(LZUNWd9=XTFCpP(2UAFXbG zw6SRVvN!JZjU{4iWF$e;AcJ`%smfw-x*UW)#ADf?APw{rCwPBft<52TtM)21NIWr4 zlg?fUvqGpyF@t}owjgEJA#h~953L!#j^xG1YjRO{ev zCL#H>Da@|r+6|+mfsC!rOSF&4O*#k<9HzmRDgE;hJ55#G>o)=4y`QU!%dt69&YDei z84asiTb(t?pqH$0Q3)h$4Hc4<=-uoeQv1TK$+|UHgHqGji`gF#`A%}Po+jlQn|U8? zM>C^+1aUU+yV?z~IL9~|==6Y1u)d0#v^BnQ!nQ&Neb}2c!msv`mG4bvo0fg`xo700 zWn5>Ql9N8k8jsP9eXq4j3zVC7b^dHO_9IigD`KBdp+7d=V}wSfC6f3XR7Z{f+&Xp^ zsdlU3s%5i&+j#6-t>Y1b@wBj4!6%$S>m>SCKileUYvsZ8jnRaQH!JSU^`%WMfR9fn zyy~2J`)|)MzVKLOBgv(tlLbVx!#5+vuDFTFI3JfRTcj(bt^3PAGf zd3BkeWv00FDND|-yd+^KmCCfzOhh;Dsv;-6wQ*+ibqqb17PN;ck&6FndV;p~-T2z2 zlSzy*hvB*YyljdEne9I^^JfvtANTq?cv#R>q9bQ1Rw2XAff@>L@p8{JRRT1lExAFy zmYT*)tlRii=4RTN!u;s8Y9F}lF#?R|Y|Q9$)ml4|d)iRPTS^G$Q(-jwE#)Nw#i0#$ z8#D)<^o&zV#N?uv?MxZdpbjjYrf7^NZz%CpKZRAb^zCA1fcL^|xHw@3Tp)sX`#f16|Lfd`PTsPXMmatr8%7ET{!X&<4A9mtGJ$ z6Y3MkP9eKO6n>Fh6~CXB4aa;BE#ZdO(xGoqv+9<6Bot?J_=lJLt8{@m%YS-tB|y}9 zM@jRh>n%ywg>$)bgtk+FFz?pG<5#V#7LI@ZL!W)w($e(9l`eZ7bL4iQa{s`-v9o-C1A%cT4K+r! zdnQ`EWI^Fn)d1}Itr^0n-^O4ldwP#>>6X5 zJk%yWGT27s4sU&EzS3Ty3#IrHJAD|T7WyNU;eb>7&>sN!v6N%yPf~S4W3pLCiM2c* z8jTG(o3S?$j4woAGusf&pBRKn%Jo}bT2XsTvM^bL^5EVLce=q+Y#i#k6}z=yG_tZe~fFxJe_OyuAe6sCCTT|Y| z%F~yB{j=-}Y>Ns&;>p#6BdmU%&Dc9MThh=Pv4H(^)yJ*Y2@@Bv>_u#A8D=r2CK4M0#H*i+~FCEz@pMK3t^=UuHNuZ(@N#m2;as zw$5o2urC=iUTLqiXSgy{Q^9PpN5iHqs5 zXQf?v9lb_Cq|1{{c>{elVlGB>q)HQeMTjWg{Hdj#0vNznb7_3Ln zF#}l3`)m)hw(@14S8pviqZHBoKfl)g=1YCV>1(ZK3~Z%C$Lb|=Aq}6m9ffuyXbb2} zN3%k;{bqTL$>a^nbaBNaaiS!6-&D+)+j72+j!_^&8Kt`2%wc5$3xaS=6#8x0(7L|9 z=IWmWKdNln{H6;^U&^02TnxLH5P_%|PDU$mWU(od6VKpXZFn2M_LE2EyNnY)#CFXU zG|R#jj~>z{Z=YQ{odP6^zc;;)NWrg}vhcxUo{4-3oa6Tdr~Q2QZyeP!AmB_?=|n#2 zt`En=2sS#hHINnMLeTc(ZOQi{Pvk@`M;Ft-g&v~11_7)*1;^SL;%g}4uRQ{X ze7~KuG+t-%JDsWiLQ$&6sESNcsIv$6M++Yo27zkO24_${Bk;x5 zxW*4SPnvg-WVsd~xY&%|jtL7!r1;b+3=uTg+mg;~vDw+y1+WsMK_X+|0MQD|WJan| z&=k%ycBz$Z7-$p8F3Yf77**GAPwTx{&3;?`xfbz@=ot~P4J!Rq?N}G>-J{SN=o6QR zu@!!mGvLe?LJsW$gCp?L;ZuMS-3Tf?DHcOSPPg_KXSHJc9EPYyjD?)ffW-6C1VEyI z3XrsbMXP1AV4-)>x#jKOTZfUk1m#s>+AU`)cGoY2Flh=eehptXjQRhg1@Q4#kis0% zO*o73zlVdOx)g&%Z9DY~j*ASZP0`R~n6;^CH=21GUV)2J0t62K)mXZsq5)_aP+iSq zR*hAIPM|q#kH?L+A`hoX~`}wwF?rE);Wy6d9^C8*-2ros38-fdwuM^-V(o z+n8yV9W*ZSJQsV%15>zClw0y*z7z9E=as7<%x*QvbYrojL3;Sm$FnEW=dCu`JLL&! zFQC#MWAu=jElOBU0Dhf|K?S}pF(-*W)8HfS%p4rj>bR`@* zp?l}@kNE~4r>^ZM!(4DHNBAiGLGK1$gtVZBt-NS=#KXbq#zpw$U3AE7MLuTL zUFDo;M4i|mr`@%ML}4g@TVaohrLNF0x}Qd14ZAT}AFr+K7`rvK(%Q1d?}z|+rCG~m z<#>AjC`=goi6>bUV8d~?!b^)7jTAWv(p6c5=1q7@B}O)$=k&N%Ys`G9ZB7xSHMv-% zo}?*7ry%8dQlY2=&Y7a54lSi`Hp{_KVv8jvVy$G+)shUIBXLw@#ed^U#sftMyKZeuql9K3AIdLG5*?{Fjj}{mOezA~(?Ltx%j+WRUadsV z@lZ0q>kI7x*G8ma9;!UlAH@(?E)ZK%+L%O57TSeOeU{oEI4Hi1fCviCF3GRceOS3~ zAURZ7ffA<(AHz&Z0g8ideBD6OKPKE}150~B&~R7vPS8w8TGnE~CTGTe9?%OhHJRc* zassNV;}<`%3+~V%e;$Ai4&1zLUAm9# zC@YhE1*iSPMl>g4bu~ejKlc2oT4=HP@;BB^b5B|K61;8kw5z+>15W+@;9Sp=m7fWP zRaC6D{gkk`L`1{LL6;f6Bh$v$5lW%(DHAFgDt;wAG{+<@`HXJH3s zuQ^04bl0}wFnpbLEcwS2XYEbV+v3mC1h1zoIcAB2Mp+7MBS=LA3qz-!x#D?5$~U$d z#)N5oyU`72L7q$dFm;I|#A;?CLvw-`B`@%-)A&6z=Nlw%u8TlR5oEpaE*EYSD=!G zG=iYk-bAXm>^FWv0_JID3W|G5XtK9DiqBc~cvh^-lZud;Tx*cfum!MfpN^m_P*xtu ze~{NpXCkazl;s*9suffWjL0M9XdNWZSvZ!GGZ__jF;Q3_w&=Y3^_b^bpK={{Pk`@Y z7A|%&Xwn;@jTRllC%w{t(8K->tw#w>Yu6@z!RF9G=waUeA|AUXCbas)+VZ@4_uJj@ zr6S49NOq9B0v2eLCoSmiGk*n_-zE>=WspDq4EX;2$KdH*qiY3BgF~CbnMWfS-KS5d zKQq8IUTT$g)?_t+4ye9?T-CQrznPbCFtzfjpFly~v`oOO&$n`_e1W8I(@j zDGqIhA66Hjy?>m@X&xa)OJH_vZ+fA{%=Ylbg&UCyHT#j?IgfA7!4*1xjFx_)o z8i?=5>`C*!j@p$rG%JWSPD-yqsm(#<6U&7oHk0EYQ9)8fpz6`{;@4LpPrF1?@3nf! zM1f!P3PWo`T%4=L%(5Eidi6KpmoM}y8gqecYjkD{ZoPb&u;p^ z9Ek-v;zz+Q)vI|etnu9I680)i`&Yp*t(26D%ra8z2kn7q0V!zA=e}?J5Ss|?HFx<$ zUZilD>~Ulf>!+=nMh%IKSjT%RNS+zL4T7lArWT!Pm_XSZ#|ueh1Wza2x`&wwM}4lA#9@N*Wx6Hm`SILuT1S@OZmI z1bskKYlG?8tW1OnVo3_Zhv5gGS4Hy_{hW)E*BF$|(0w8#=A|t;;s=)k%&u+I8<+Ai zSxp*?(|m8`*S$@cm+hUPV)4+Ws0QC{c|the-PVKJY%+3KkMx6j;Y6|w4rzg^Kwnk> zE%W3Qqrx>3Yt6|!&A-JOt1qc0b%+&o-us&#+yXA*lM(D(JB0Qq1pZrN@IU$wf9mQl zlwB~@ITpESfk~Q%alxrwGz<=ylOE61LYRl>4)J@V>*UzgpvL!NP)ZD?`oz_^BllC@ zD@3uQk~UU$azOK!=k0~7cST6j10(KmcKSLR#t5vo3bMw$XRWHoh3AKg!`wgF?G>INKN=jmZJ})=^+47Cvmn9YpeQuplpL7OyZb+*7WfIvSvu)BnvRi3zy z)a;Y}YDsZd*T14E|G1)y+Sr>9>{xKWeP_nPU>)s0Yv<-h#8o;n?}Z%A0~Vj0|F!)8 zPq%y%94YEvll$yXb`$Z2eQqF~Fz6R5Azw!!IHeK{L*|v{>+K?PIZdkU)JHdbT9%(_%q>GzN#^ zCbv(-hpS)Gz>b+{5gU+Unz_UiL6X1EA;|7x`OQ5;-Ze4LgGLe8!`Tc-1VinKx&^!dO(Ua$^^kq4aygU-l? zR)+JxsY?H@Oa5QRUd;+4zF_8{ZOv95x0v=RVxc6gieR&yZ{QZZopToEQt z`Dbu^KUVb63a{sW5VLz9G&`x~JXw(T=#lEMF-2+Lx;Tp$0LlBhDTZZh^4|SJS-_}0 z37xfP45wFNG|0qhSAh1KQ6c&~)kn4`fE_d=v36|5{R76Pc_@MH==^N=-2p(YEU`0h zKQ2WNZZktLCmQg8AuAK`Lh?xpgYY7w9S3TJ|~9Oq9b8>phnB7%H&%;^wTZQL1}8e}o{h%F~_l zjKYWfdpFJ|)d{@xr#$7EhON;kb)SYP4ZK3y*o(WjFExj09cXIq{%h6v9}YQ6)Ebs^ zYdLSZJ`!v7qa;C|VHFM;40uTx_KLFWrIqBF-^ROzo0^!on2KbFgz}`K1^b38iH5Ww z#c0U@)B50&Bd+S?Gx<&U_c?(?oSmbZ#z?tOXA*;5*4}1#2EWndiM&RVQzA^hb6{E(MXIIZ9ukE`S#n0qn1__q!KL$+ z%uPyn9CXsNdta6PPeW$*95yPe#_XrV7c2y=Vf^~K zBY$v(u=Vp2WgrKvQXvbPBTbCJ>-xp-JLq1bE5czTMKEX#DhKK}ro8st3L?tO5`K38 zPQL}**C=HTP1*A|q$U>Fb)+(TOYK%2EXSJxg$7f6pm=rIb8qIRstvUfh_NDz zl}e^sI@!3TcI71~?x|p<&OIBx%f~br*9H=f@}I1S!SS-KpjOlX+D&aG#6j>|yefX&lD z#eH&-tK++{VGZ}e_}JNCMm!jp(xAaqx=7~y;qQZ-C@JNn&PKEniJP82^!u{P>8R_-aQ;ng^cEW=%wlkl=^dkdAjh12OnS z$R$vX5*8!nqldb%QUssMAEK{0L(*do=nA{;4}xG>^f3heVn5#`Jr;w*YxW?|mZKm1 zwC`^LCVVjC84ef3zv??ShuAaN+tyk7rc(4{>=`l70P)7Tq=4P{yl7c`k;cor#l&I! zl56n%qwFWL2;mV2{;aPMUG67w8kE)sVcpNrg-3Q_*?!`@h}b0_5yrer&J6{g3up=j zq`|jNVdeOjy|aqQvKuJyGs}s!V(<6=VjcCp`e1!WS{C>3(UHG*@Nm+Uk$}!iI+vZh*-X4? zA4hf7PGB9y<2dgux2`lSBB}m4?n9nD^6dXBnC>)PGVFl8w$ zxmUc_?FUUIp8;PJb7skdO3@!+aaC|OrjEVBj7}}y!?|vH-+dPC&ed^$&Bb)-7* z{M*BFHA7V0XpOsX_cAV@;blau{w8>_I8$>--o6d*~2mWX>F$ zA`n1{UWMdg!TsJIq_9pW)49a;KxfafUr&i$*GFXXy!3Oa$dOzp?g9eTn&o~1Kj=59|h7HP>d#a`AK>VtSL*s^A$@3p4^9ufI>Ypy@W{q#l zolf_~w%XL-cif8%>37u2aB{DC$?kOI!MpOMfn>HuCP0h`5`BX~1&x=LI&!klZEiI7 z&t8_zrBq%Yul%W&chS(JzrBs06kdBtL!+Qwa|^I3R^)OUl2$#NubQl`fo52tla$L%);a6v+$SV@nMg4!M4!K0}{x)h!kuuYJEo+@ga zC)T}2guVVSdYv>BWjBdlvFLZ`nN9fWQmi7k>+XzdpkAHM$@NDHu#kzj()JXTX`dnB5}Rgs8?$;-)H(RBN^zYX?o-uqOI?$J z8!`rbsN{W1T?6me%j7Q#E~gE9nFp7*?}eh9cDy;;OD^59grd<+QZfgQ>q05k?~f#W z+C6<32IEXepe=Qgo^Fd7r%|>6qM_F(1z+|Qb)hpVpY-1+yh%{i)@Cd)HC5FeQBqiu z3Jyl{1fEjS($cEx>E-Wz?0_khA89bcR0{AaFHK?NyOGd?H8m%v+a+0(zTpH_1A~}^ zq=2?ny@Ro$IN@BkQF+npYA_P&539nz$o^ zhbrBLN>x?8@;wLNTQ04fpXD3XVlWQHJdIRjbI+sa)iD)0fBk}wMtK$pul93~)Kax0 zxXXN|ko>44taEjv)%Dt=rlAaME?E+N#U5)*`F$Vi!BOV7-;95L@REyxo3L zxy@`)cQwN_8h6MpQDD{y7rWZfPV?mpO^s*XcE?l9cKdA<4G0wVGEchhD)U$&?BH-~ zm04G*?qry;;#9zgRzkckZKbYcdlMCVysD@fJ1ZMy+$D@oRK7gv)J{wjt3SJ;a#*D* z{xr5i;>WqaM%*HMPav0s)A~{6Mx1d!nf^^#smV;PD&w3j1f@V#xA`Q?qY)|ew?W^u z3%c9aUXhte+8(7tNFzYu2HYR{J%uNOf6S)u%hviAxb{Yg+BR zTY0Z+ZP9J$vYM0EF>Gou#F9@wmd_)0wO-XKse^j14j8xm2|cx-s3O_P^OTWK=mxc8 z*BMBVIYq}){$ttn%i&|jhDN1HLmYzzy~jgFEJc+kB&#JghOmi83T z@>X6%Y{L2n@^E%8Wdv1)4dDUheq(YGw{Ls5gK3NxR%X|~BUU?5i|FzMvQf@2t%Mrf zJI{ZH$ThANR7~`56^%=LJPHbJ88V3-AmE_GVs)9Zcey{0LrDZlWgUcK=|`yjLP+sF z+|7zy;^i2uOJR)=gMJRhc-bn5!jvT~vb{dwp zcL;K*TvJQ(VSJ|e=mxM>M*w^2^uGfWEU`bfZ|1z=s3!A^5N@6XBrd|_YR1D^8ZAS2 zc4Q8Isue)DXK1x^!=>GsB%Y62q!n^B^r`zMgqUbw?&G#?20N6qjc2=SpVJmTif27; zTWrcDjr8-3G&E>#Fn{W~L8Ds{a;S{sbL{ozjvL&^BlRutL=g!D}) z0gE6Rr)U1-W{dT97Y)w!zR3oT~R2X+QFCxo6I?ap)rrbor|1(q~%xN4O=L zG)E>{kV#X|#}?Jf^6PscXQ+zw@TVk0riW8&PtFOyX}?c@K8-D;fhLFF5adLOypT2j z_S#5rP4|+WSx;vf$g1{$6WzDz&!P%K8M5tc`y@qCEON2Xja`C>flkO0TQ|;UxbADN z$jQ}69=_#pXS$JaP2vu3`yMmheq;L5_VI2HMpla|Wz-`IRD7s=zn6CK6Gp5a#Hwu9 znWNt^7wJ^+y|2q!nZ#6CcG(N`muNhS+IQI-H#2nOjjn2Yn7y#A(>|XLBeb%Yd_(}V8(-}Q7yudV=YiEKn!EMje z(X@yK9e56=+CwW@f1}PDI*6CdwIJ}9T*nRR+$jg4?~NH!&XI`D{D|T`#>VhuMAfX~ zfo4`)T^)unUoC(5@WE-33S7_XVjz6;OO9AXj;zGx^m{WA@d#V zR#pDWiso^8N62|-%YbLzDwm{ha!b)_y(t^!`D0eer3794aCp2(tb(y0c=-Dc#*Ma~ zg1;xj*d^x8?u5=js6{mWK$4bg=K<@J>gX`l+iAec-TP^BdSn&-O)*j9ob{u{=#o2# z=OLhMYU0R#BITW2B8c3XVs2&GC93K9>3%RfAc%`nmhdnXVxK|bXJ6lFxv(LR7)9#! z6My@_v0!gzd!f+sOb@a^9(dVL;rQ{eZ3^<|yvV@f@(4k#?4&(hUC%jv7W3pyhhO1% z*!{+fQ({%zuPmYRfd56~3?a>bJrrXwosWr1^@V)xL ztY+w)XzIR^x)w|Mh7QZ&@LQ~esW_hVF)F?SkalU-!?u?0gy=1cn#U|Js(mReTfl?d z(63Lt?@kiA%0NI?{^HR#|K14`z>F^Ir{Ki>k(M!x95P!q%Q08td%#rcar;F00eSR3 zZ?k$kcEOwNE^29kpDetstxa)Kwm)BVz3PQt;4b-o!$XYsRn&C#LoX+frSj@+`%d!}??|j{L>t%IlNg4ox*T zkKyN$06Gl2{Kl4l%CA28FhGv#Q?u!MPyV}g?-`^BKwvWt8B~*&g62D~O9TtidcNZ9 zvJ*hZ`+oaPWXsZI(XI)L>$z0yTwHDpp2&(Kz%If~8q+l)cNgcQ5OE4&5~m+y)WRu^ zY~~_TedV0kp~(kt!Y*n8w);w>ax2{#GvCkVJWO%o#c^{}R?g79e$zKH{H7!9@@w*(lzY77x1<1NcE^D{SMr5(E~MEwZo_if zyT2wohf#snT~Z45asXEph1fxnIzs2~LT%E}NU*Ichw^YVM_!b@{Ltg3I4@7FO7{|P zcVrmHF`&cNy;%z*c{W`W!2vCxalZi+qL{b@D1(1rF}W)J@0Tn+%ArUEuOMZjtqYm8 zUX&a)B?FJBI!$15m%6|{l)7porgtXzGsWyrd?C`D;T94bQlGfz+W4e5aEn3MF!7YQ z4r!c%n;5nPsiUGuW)>OBJY=9YCO7{mxBs5ny~@m66rE5j!oX$ghaQj~0*z)m$<)L+ zAR4cjGPiiAH_6xS=!@c3JC?=CnTz2o@T&*4=YNvvqE-~?vS&23KrstfyL7gZ4Qn+$g6BA-2*4NJG2VaLJfByak4rq(B7)7SuyH;@eX z^(4b5tzCqtBtZhS!i{4_Ao6SplH>8a!bl-9>QBfKvCw^ zUS>!~>2J(ANY+OM%Mwl2fEsK4Ic&^vIFBA$fLh;Bf56EMJ-jv>){oT)Y2qhW3o7FbN zipV+=bUNirh22Nj4-vx8A5r--2=(_L{S@k>I(Qund%j=hAd}6$Zap7Mqcdu~{Ly(1 z#Cpbq=Ugn8S0_fCOz@I3#0H;=0Dr6*1fjNBy9J9`I~+L)Zzx+o`oDP~`u{AJklis|bD|23U#xTX9~uyLWM4Ym6{QSy4cx zatfkE8z$7r&#oNmkkBIb9SC2po|PWqj@{vZ)3qkv z27IF`k$Jr$~N-Jd|zk2>I?0`|h54R8HHz7NsHs zWf2mQwLt~X=c9uaA^#AuU*QTWaRug_0e`QmQx%+&E3kEytlM317ovXFSC=H`ZHQEf zGhCprNBZ45o9>YiB$XxLSF~ppA++yjL#f^RTz_S)p)OOnY)>#93&V1fg4M?Kg2QDf zT`dO`hcd6p8vi}x-i9FEP*@UP8yWRMz9uy}SAC$lPh8%th%pEHg9sZ0o=N;}!~SlW zO1SVx2S%o4QTnWi%DAWsszmrVLP9mqr(U(Y)T!?&i_g+Q0&f77ucu&tPUlr~HE{&| zvP5b3KgDeWUL;d)YtRZIiPsPB?^3`;r57aphdvGve2N~m*~+is(1I?oW>p#Pl3JSR z$yIP4Aw#=;5IRM|9d-O(l4Y zhLDS^LAiMDh6zseOY~bxALU0Nxs0YkolDXzFtzePE{?VhKRLtA%dR?qcVJJ=Z6Q^y z-M-ef(V#S25GPvIk3gW=e!dhErbu&Ky-T8?yda)t-l*X9(nvnL(GE`By}#6sLpY1R zb%r@Dth$W$Mq$+Ko;ioV&3sCjy|LJ1gAX8g2TVARY~Axjp)08g&j zKf0e9yXE@*s;e3L9`AEdpEO3m%HLSMA1W$t1o!$IVqWb&Vhii-stNcPowdOtld@-1+p;e4jL7bOHm;77xKU2+3W{Y zQrk)o?K3`VM3LNQfTz4Lr=;uFL$!UUv`jQ@ki5ix7q1Gw z=&??z>N9!%RKCoJ=sCRpa^DpeqW1Cv_8YGDgJPz>(fzq1M}n8-xqq-HJO}xga78&9 z1u-|t6m(A>r1boXaZG+>V`IJ7wDGKb-uj?&w~jlp{m7{d&Cqure^+->RqCIh+qUR? z>c|i*U0B5O&Fy@Z>5zi!XU-@5s<;(jm|!b(T{N`+Y+&%}5;8O8o#e9QN+QjZ+lw1@ z!o4&P6g;M$v8ig)@A8>X{kz&1A_J(HASAv*))u=00d_02t0d&B8zuA41ybT$`! z>Td9UqvMDS`F6qd!Mq%EjN_mSVd0Hvn`qA`6Cw*f1%L#Ggz#v6}$ zJ&t=1Jo+E~o*1tVt_m>CCO-s(zu|Hkh7{)6FBgCtqp%hzgU(dL=@Ay0m!0L@yIIJZSME|InVLXEE6q1 zOCc)5LZI|g2m@okg4w;`g{kno?bFa1zfa6%`CILq>+5hrV5<}=2kXzo6JcbMc54j0 zK#ptIT)qIB>du#a;)QG)f;mMdw2s5lKH=O_gnsOae{)juHtO+-016h)=10W|U^lhc zrWES|6z^~ME4V~E+cN7Vh9RaR^CLzlTFoLjRiC$vS{R?^REAIZ_g(BSaGUFS-^A*!s9~N{u$U!nGyjN9Fe_n>XSb zZBDvb+YH)?mJ}Xrij_-Ee#{^e|IDsu>0`p^qa4stdxtP%NarQP$T6LrrMI|u^G%{S_j1yE}zdWe(T{h?xllm8VAT;_l z(UQZCvVbCFVCl(3xtGDWTD2f%GO9rB7?EdVyz6ODIrQeLc$vqaZmBc>Kkg#Ah6OR6 z#_XGOBBp29oA`PiRH|dfRt3S*=Mi?bN^zQi+dS>(OsIr^#Ff;jDU_P2`z11VPP&ZS zf0qiTT%jvQR8B)m?9w$Si<>gSNsv^qynmyz9rRAkr$1XAu$TXed^W*gSz(FwDYMNW zH`?-YG^0@MaYdG{)&~@>?y3p$O4P`5{5hF4Y2!Ne0RO~)!D^RNdX_dEFH!pZmr708 zEnDN%q-C@OR5jlAgXRIYH;!+N?F@aUa-CqHyJ&58O)u;fXQ9nS&iq&7W*bBwv^eG=LUZ1?8u(KVpKpmj<6A!YLpcqv_Zru* z)$Zt!Ux(jdvR;Q)0KAQA!*&~Ij6cGft;9>m+8Zs*_Ac7+Fh3ZcFX;P9;?6 z)=vZ*@z;CrSnJ+lI@>!|ZK^nz!VjM04}`Iuh*IGxA$89o`(~QfRWAdN7{0aHE}{+T zv^KZ(T3G@)4@-9!wz18AnGnuF`{IWrL$W_=dYXgPBMaa)MhEzh(M?Mf9Sp*ryuss8 z>B4JYE`ySaxYzKw!aJ*`MXZWRshqZ8LlUu4)k1~x|Mkb!5P zJUQ&lX25lrHM{o!DrpO4TybS21IR6#OSYoos0>RfQZkE#_ISLm+7%#B_n0x4?Q%*{ zl;7YGTBb_=<`&xsCcbZRvJ%HroeK$Z8d($m zMt$D#U$E5MFOV*1*1MZ(b%Y`<*%4_9v>;~)7Wm)eFv^sMaqHG%z+QAAxI z5t8MXycA!a|S|9dIWDHhh{HdgY9QWXEq(QiaXhgyqV zjPRQiF86|q8_o6$CYx%Q?y+3BNU9b5V5RW!3X^l9*{NH#?p$zzsahm-ih=D6{umaS zs>m!u2_*0GRMPnz-!6r?i##IvU7?va)or?E53?ckPYsMo0fi781)eNWZ6Za!IN!1M zRDFzG*zaa;jc$WwAWsJG0jmKpjcsmjjsxK^3$aB{%{VGb#X(e@FdgOL=;h*cdDRL% zUKS`;gUXrehZ=lSHqFGmDeS}{L^>9Ipf=( z9uKVJ$BET)4QVasjQCq^GrHA+UNBqRPr%zQn0t3JK;KU?|DZP0q1B7>CidmjnQijs z@pr{#0oY_tP?J;KG(X5?>%N<^#RzQT`^vIwy{JlXpKXD{(%TRai272j`JX`_icd8l zK5rTO*QTvTlpJrdvfKQSw4m=pubijr$O#!&Efu-<(Cihqut*=Zd6I6UdDQyJ#)t<6 z4;{p-yxiHhF1q(;bm?Z}Sy3R`yQ0C9iS->`QkZ=MxO?{}o zh5^5D&oy2@E3jGIr63Wb_~?{pu+~S6vrNS2WPl#l6a*~i@lm`*by^t9pVq?giSOBO zs^|Kx!QGGY`KceV=mm~{^{I&qp?P)O%gh70(4Kv^b5zqj#Qn51Y%RtzSVxm(iC>%F zF|P-RqheatOdtuG!uHeo% zf66uqL*EU*x!z+jy<2YN@L8Pv9OFuksJirB+o1II%dm?_s7rx9@XTj2WMDaYNDxwT zEkba569|L;<7DIVTIVjaWx-(SdXXy?anY&C=Cp8RRtUowbr5fRY=2H?_%i+;QS03s zXmMM=O`&4fYffQ`RQfo;KnDl2S^5wEI9boDSjvw{G%Ak>aitQxVe4{@-|gaY!0ED- z-Ln|{a%V+mTM|vHRe=-m_BWoMxhr$`wMOZZL-WTp=(M2P?a5%C^>T$F=<;*vp?l+Q7lPdFfaPjrxO24|qUt2ePic-r*C}gY6LM;tIqh$s_t1y^_@EFYNMWA@ z{fB$qygC{APi^W%X$HmY@(}OfF9-2I!PNeA7n*nO_hD+KFL^8uhNBz16~v} z22XxP4qrQ;3pF{qLy&<%Ut~#hy=u{3&hn=Eo2O)okH4*}uFF zJ(Kd>iFx}2o19VPg^Nm@4cA_Et4hUo>!MjLbG`$;;W(-TCPNzcxDoCoFCbmPSI(tb zt=S=)jm)^$JDt_5lFJWl*y1b{p$!CsMoVF495(~w;?@J)D5KJnem`0mzE9@4j9*8dr;=0iC$P@p-Dz%Zo_+Le*iycv5H zUyc05?b$BvXWDFhZBf+GY^TEB)6T+|hx@jI`g19d%Ss|oNDy@^BzX3qtP`HR>SGI)gn1t?p14jpvZ|F?s_r*1Dg8;4rj7r4(2(RsctSrJx@kBnd#8j=6FelBAh?y_AkX!!8bD*@oOt12r!YvXRi;WzHkWdRA)(FsyF%q4 zwMiF|uLr!pBM{<=_BCA^n*brEAsfmx;@})BufBFK$lE?ccRWEy{Xc8#{4u?r6?ypg zF+&*Q0;KPhy-rJYau*E=K5{DkSbMOK9Rb}hP=Qz;)d>`!-hL^+S=Y4P#^ma*P9xqX z2k%zs(iwDts%Xpd!D!OVGS(Q$4hEGf=C_q~3MpKo{)oaH4ZHmauXSrH(m&<55G*<*$Kb+i_%X{+Adf2T_LiFPbPMh;DPibwW!8D_ zldHPm>$G#{bk1+2bzZRj)1uzdQqhWU<9K4{w-==m>4E3!E3b>RpY4Y3(F6w@|GZ~6 z%6D4NxkBS&8d*`OP$NDS9Z=SoBi3mhaiA-*tSC}pHGw7-Rz$g}M<5_=Xn(epGvXJK zgcfd~Nu3#mguCwKp%t1qOqA<$_)*SWCT(mMf6Q_6I)7P5C^WzBdn8Fo~;NG z63e5&!J0ewANm`Kvp()WMKz!P(CZm1I`21d3!$aC94}I#QE=0%`0sC}HPZ94F^pwL zasaH%Q*9d}%pC=P{zIm!`7w9QO-6fb&NDyR9fqMFD;-Ri3IOUeB9drq61%xE2!tO$ zGEL)(d~kM%O|qCfW*tjROdRSZvo-0}FfD^*uVZ2z+bU3xP6l9}W{VK;BqdvEWw_t* z8PcqA{d9tZxQq?paREb!OeiNXm;FggZP<}(*n`UPgEiiOBU)vc+O)OL4 z>4Q<6sjoG^*c2W-c{LTMUb)6ijF$;IoT^WK*KSk!)+o=x�b>#m^a&nd^PN*X`zK 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

@IyzwQ-cSZ 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�b>#m^a&nd^PN*X`zK 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