Skip to content

Commit 2f215db

Browse files
authored
feature/utils (#23)
* channel * kagome-crates fixup * update cache * multiple path fixup * rust build fixup * bandersnatch -> ark fixup
1 parent 26b68de commit 2f215db

21 files changed

Lines changed: 1018 additions & 22 deletions

File tree

.ci/scripts/init.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ main() {
1313
linux_deb)
1414
echo "=== Detected Linux system with apt"
1515
apt update && apt install -y $LINUX_PACKAGES
16+
if [ -f "$HOME/.cargo/env" ]; then
17+
source "$HOME/.cargo/env"
18+
fi
19+
export PATH="$HOME/.cargo/bin:$PATH"
1620
;;
1721
linux_other)
1822
echo "=== Detected Linux system without apt"
@@ -31,6 +35,12 @@ main() {
3135
echo "=== Unknown system"
3236
;;
3337
esac
38+
39+
if command -v cargo >/dev/null 2>&1; then
40+
echo "=== Cargo is available: $(cargo --version)"
41+
else
42+
echo "=== Warning: Cargo is not available in PATH"
43+
fi
3444
}
3545

3646
main

.github/workflows/build_and_test.yaml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ on:
1818

1919
env:
2020
USE_CACHE: ${{ github.event.inputs.use_cache || 'true' }}
21-
CACHE_VERSION: v01
21+
CACHE_VERSION: v02
22+
CARGO_HOME: ~/.cargo
23+
RUSTUP_HOME: ~/.rustup
2224
CACHE_PATH: |
2325
~/.cargo
2426
~/.hunter
@@ -43,6 +45,12 @@ jobs:
4345
submodules: true
4446
fetch-depth: 0
4547

48+
- name: "Set up Rust"
49+
uses: dtolnay/rust-toolchain@stable
50+
with:
51+
toolchain: stable
52+
components: rustfmt, clippy
53+
4654
- name: "Restore cache dependencies"
4755
id: cache-restore
4856
if: ${{ env.USE_CACHE == 'true' }}
@@ -62,11 +70,27 @@ jobs:
6270
else
6371
./.ci/scripts/init.sh
6472
fi
73+
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
74+
# Ensure Rust is available
75+
source "$HOME/.cargo/env" || true
76+
echo "CARGO_HOME=$HOME/.cargo" >> $GITHUB_ENV
77+
echo "RUSTUP_HOME=$HOME/.rustup" >> $GITHUB_ENV
6578
6679
- name: "Init all dependencies"
6780
run: |
6881
make init_py
6982
make init_vcpkg
83+
84+
- name: "Check Rust toolchain"
85+
run: |
86+
echo "=== Checking Rust toolchain ==="
87+
which rustc || echo "rustc not found"
88+
which cargo || echo "cargo not found"
89+
rustc --version || echo "rustc version check failed"
90+
cargo --version || echo "cargo version check failed"
91+
echo "PATH: $PATH"
92+
echo "CARGO_HOME: $CARGO_HOME"
93+
echo "RUSTUP_HOME: $RUSTUP_HOME"
7094
7195
- name: "Configure"
7296
run: make configure

CMakeLists.txt

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,42 @@ project(cpp-jam
2121
LANGUAGES CXX
2222
)
2323

24+
if(DEFINED CMAKE_TOOLCHAIN_FILE AND CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
25+
if(DEFINED VCPKG_TARGET_TRIPLET AND VCPKG_TARGET_TRIPLET)
26+
set(DETECTED_TRIPLET ${VCPKG_TARGET_TRIPLET})
27+
message(STATUS "Using vcpkg triplet from VCPKG_TARGET_TRIPLET: ${DETECTED_TRIPLET}")
28+
else()
29+
if(WIN32)
30+
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
31+
set(DETECTED_TRIPLET "x64-windows")
32+
else()
33+
set(DETECTED_TRIPLET "x86-windows")
34+
endif()
35+
elseif(APPLE)
36+
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
37+
set(DETECTED_TRIPLET "x64-osx")
38+
else()
39+
set(DETECTED_TRIPLET "arm64-osx")
40+
endif()
41+
else()
42+
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
43+
set(DETECTED_TRIPLET "x64-linux")
44+
else()
45+
set(DETECTED_TRIPLET "x86-linux")
46+
endif()
47+
endif()
48+
message(STATUS "Auto-detected vcpkg triplet: ${DETECTED_TRIPLET}")
49+
endif()
50+
51+
set(CMAKE_INSTALL_LIBDIR "${DETECTED_TRIPLET}/lib")
52+
set(CMAKE_INSTALL_INCLUDEDIR "${DETECTED_TRIPLET}/include")
53+
54+
message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
55+
message(STATUS "CMAKE_INSTALL_INCLUDEDIR: ${CMAKE_INSTALL_INCLUDEDIR}")
56+
endif()
57+
58+
include(GNUInstallDirs)
59+
2460
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
2561
message(STATUS "Boost_DIR: ${Boost_DIR}")
2662

@@ -32,10 +68,9 @@ pkg_check_modules(libb2 REQUIRED IMPORTED_TARGET GLOBAL libb2)
3268
find_package(Boost CONFIG REQUIRED COMPONENTS algorithm outcome program_options)
3369
find_package(fmt CONFIG REQUIRED)
3470
find_package(yaml-cpp CONFIG REQUIRED)
35-
find_package(jam_crust CONFIG REQUIRED)
71+
find_package(qdrvm-crates CONFIG REQUIRED)
3672
find_package(scale CONFIG REQUIRED)
3773
find_package(soralog CONFIG REQUIRED)
38-
find_package(schnorrkel_crust CONFIG REQUIRED)
3974
find_package(Boost.DI CONFIG REQUIRED)
4075
find_package(qtils CONFIG REQUIRED)
4176
find_package(prometheus-cpp CONFIG REQUIRED)

CMakePresets.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"binaryDir": "${sourceDir}/build",
88
"cacheVariables": {
99
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
10-
"CMAKE_BUILD_TYPE": "Debug"
10+
"CMAKE_BUILD_TYPE": "Debug",
11+
"VCPKG_OVERLAY_PORTS": "${sourceDir}/vcpkg-overlay"
1112
}
1213
}
1314
]

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ init_vcpkg:
3636

3737
configure:
3838
@echo "=== Configuring..."
39+
export PATH="$$HOME/.cargo/bin:$$PATH" && \
40+
source $$HOME/.cargo/env 2>/dev/null || true && \
3941
VCPKG_ROOT=$(VCPKG) cmake --preset=default -DPython3_EXECUTABLE="$(VENV)/bin/python3" -B $(BUILD) $(PROJECT)
4042

4143
build:

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Build
2+
```cmake
3+
rm -rf build && cmake -B build -DCMAKE_BUILD_TYPE=[Release | Debug] -DTESTING=ON -DCMAKE_TOOLCHAIN_FILE=<path to vcpkg.cmake> -G "Ninja" -DVCPKG_OVERLAY_PORTS=vcpkg-overlay
4+
```
5+
```cmake
6+
cmake --build build
7+
```

src/app/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ set(BUILD_VERSION_CPP "${CMAKE_BINARY_DIR}/generated/app/build_version.cpp")
88
set(GET_VERSION_SCRIPT "${CMAKE_SOURCE_DIR}/scripts/get_version.sh")
99
add_custom_command(
1010
OUTPUT ${BUILD_VERSION_CPP}
11-
COMMAND echo "// Auto-generated file\\n" > ${BUILD_VERSION_CPP}
12-
COMMAND echo "#include <string>\\n" >> ${BUILD_VERSION_CPP}
11+
COMMAND echo "// Auto-generated file" > ${BUILD_VERSION_CPP}
12+
COMMAND echo "#include <string>" >> ${BUILD_VERSION_CPP}
1313
COMMAND echo "namespace jam {" >> ${BUILD_VERSION_CPP}
1414
COMMAND echo " const std::string &buildVersion() {" >> ${BUILD_VERSION_CPP}
1515
COMMAND printf " static const std::string buildVersion(\"" >> ${BUILD_VERSION_CPP}

src/crypto/bandersnatch.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <memory>
1010
#include <optional>
1111

12-
#include <jam_crust.h>
12+
#include <ark_vrf/ark_vrf.h>
1313
#include <qtils/bytes.hpp>
1414

1515
namespace jam::crypto::bandersnatch {

src/crypto/ed25519.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
#include <schnorrkel_crust.h>
7+
#include <schnorrkel/schnorrkel.h>
88
#include <qtils/bytes.hpp>
99

1010
namespace jam::crypto::ed25519 {

src/se/impl/common.hpp

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/**
2+
* Copyright Quadrivium LLC
3+
* All Rights Reserved
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <chrono>
10+
#include <condition_variable>
11+
#include <mutex>
12+
#include <shared_mutex>
13+
14+
namespace jam::se::utils {
15+
16+
/**
17+
* @brief Creates a weak_ptr from a shared_ptr
18+
*
19+
* Utility function that simplifies creating a weak_ptr from a shared_ptr.
20+
*
21+
* @tparam T The type of object pointed to
22+
* @param ptr The shared_ptr to create a weak_ptr from
23+
* @return A weak_ptr that shares ownership with the input shared_ptr
24+
*/
25+
template <typename T>
26+
inline std::weak_ptr<T> make_weak(const std::shared_ptr<T> &ptr) noexcept {
27+
return ptr;
28+
}
29+
30+
/**
31+
* @brief Thread-safe wrapper for any object
32+
*
33+
* SafeObject provides exclusive and shared access patterns to an internal
34+
* object with proper synchronization. It uses a mutex to protect the object
35+
* from concurrent access.
36+
*
37+
* @tparam T The type of object to wrap
38+
* @tparam M The mutex type to use for synchronization (defaults to
39+
* std::shared_mutex)
40+
*/
41+
template <typename T, typename M = std::shared_mutex>
42+
struct SafeObject {
43+
using Type = T;
44+
45+
/**
46+
* @brief Constructor that forwards arguments to the wrapped object
47+
*
48+
* @tparam Args Parameter pack of argument types
49+
* @param args Arguments to forward to the wrapped object's constructor
50+
*/
51+
template <typename... Args>
52+
SafeObject(Args &&...args) : t_(std::forward<Args>(args)...) {}
53+
54+
/**
55+
* @brief Provides exclusive (write) access to the wrapped object
56+
*
57+
* Locks the mutex to ensure exclusive access and applies the provided
58+
* function to the wrapped object.
59+
*
60+
* @tparam F Type of the function to apply
61+
* @param f Function to apply to the wrapped object
62+
* @return The result of applying the function to the wrapped object
63+
*/
64+
template <typename F>
65+
inline auto exclusiveAccess(F &&f) {
66+
std::unique_lock lock(cs_);
67+
return std::forward<F>(f)(t_);
68+
}
69+
70+
/**
71+
* @brief Attempts to get exclusive access without blocking
72+
*
73+
* Tries to lock the mutex. If successful, applies the provided function to
74+
* the wrapped object and returns the result. If unsuccessful, returns an
75+
* empty optional.
76+
*
77+
* @tparam F Type of the function to apply
78+
* @param f Function to apply to the wrapped object
79+
* @return An optional containing the result of the function, or empty if
80+
* the lock was not acquired
81+
*/
82+
template <typename F>
83+
inline auto try_exclusiveAccess(F &&f) {
84+
std::unique_lock lock(cs_, std::try_to_lock);
85+
using ResultType = decltype(std::forward<F>(f)(t_));
86+
constexpr bool is_void = std::is_void_v<ResultType>;
87+
using OptionalType = std::conditional_t<is_void,
88+
std::optional<std::monostate>,
89+
std::optional<ResultType>>;
90+
91+
if (lock.owns_lock()) {
92+
if constexpr (is_void) {
93+
std::forward<F>(f)(t_);
94+
return OptionalType(std::in_place);
95+
} else {
96+
return OptionalType(std::forward<F>(f)(t_));
97+
}
98+
} else {
99+
return OptionalType();
100+
}
101+
}
102+
103+
/**
104+
* @brief Provides shared (read) access to the wrapped object
105+
*
106+
* Acquires a shared lock on the mutex and applies the provided function
107+
* to the wrapped object.
108+
*
109+
* @tparam F Type of the function to apply
110+
* @param f Function to apply to the wrapped object
111+
* @return The result of applying the function to the wrapped object
112+
*/
113+
template <typename F>
114+
inline auto sharedAccess(F &&f) const {
115+
std::shared_lock lock(cs_);
116+
return std::forward<F>(f)(t_);
117+
}
118+
119+
private:
120+
T t_; ///< The wrapped object
121+
mutable M cs_; ///< Mutex for synchronization
122+
};
123+
124+
/**
125+
* @brief Alias for SafeObject with a more descriptive name
126+
*
127+
* Provides the same functionality as SafeObject but with a name that better
128+
* describes the read-write access pattern.
129+
*
130+
* @tparam T The type of object to wrap
131+
* @tparam M The mutex type to use for synchronization (defaults to
132+
* std::shared_mutex)
133+
*/
134+
template <typename T, typename M = std::shared_mutex>
135+
using ReadWriteObject = SafeObject<T, M>;
136+
137+
/**
138+
* @brief A synchronization primitive similar to a manual reset event
139+
*
140+
* WaitForSingleObject provides a way to signal and wait for a condition
141+
* between threads. It's similar to a manual reset event, where one thread
142+
* can wait until another thread signals the event.
143+
*/
144+
class WaitForSingleObject final {
145+
std::condition_variable wait_cv_; ///< Condition variable for waiting
146+
std::mutex wait_m_; ///< Mutex for synchronization
147+
bool flag_; ///< Flag that represents the state (true = not signaled, false
148+
///< = signaled)
149+
150+
public:
151+
/**
152+
* @brief Constructor that initializes the object in the not signaled state
153+
*/
154+
WaitForSingleObject() : flag_{true} {}
155+
156+
// Deleted copy and move operations to prevent improper synchronization
157+
WaitForSingleObject(WaitForSingleObject &&) = delete;
158+
WaitForSingleObject(const WaitForSingleObject &) = delete;
159+
WaitForSingleObject &operator=(WaitForSingleObject &&) = delete;
160+
WaitForSingleObject &operator=(const WaitForSingleObject &) = delete;
161+
162+
/**
163+
* @brief Waits for the object to be signaled with a timeout
164+
*
165+
* Blocks the current thread until the object is signaled or the timeout
166+
* expires. The state is automatically reset to not signaled after a
167+
* successful wait.
168+
*
169+
* @param wait_timeout Maximum time to wait
170+
* @return true if the object was signaled, false if the timeout expired
171+
*/
172+
bool wait(std::chrono::microseconds wait_timeout) {
173+
std::unique_lock<std::mutex> _lock(wait_m_);
174+
return wait_cv_.wait_for(_lock, wait_timeout, [&]() {
175+
auto prev = !flag_;
176+
flag_ = true;
177+
return prev;
178+
});
179+
}
180+
181+
/**
182+
* @brief Waits indefinitely for the object to be signaled
183+
*
184+
* Blocks the current thread until the object is signaled.
185+
* The state is automatically reset to not signaled after a successful wait.
186+
*/
187+
void wait() {
188+
std::unique_lock<std::mutex> _lock(wait_m_);
189+
wait_cv_.wait(_lock, [&]() {
190+
auto prev = !flag_;
191+
flag_ = true;
192+
return prev;
193+
});
194+
}
195+
196+
/**
197+
* @brief Signals the object
198+
*
199+
* Sets the object to the signaled state and wakes one waiting thread.
200+
*/
201+
void set() {
202+
{
203+
std::unique_lock<std::mutex> _lock(wait_m_);
204+
flag_ = false;
205+
}
206+
wait_cv_.notify_one();
207+
}
208+
};
209+
} // namespace jam::se::utils

0 commit comments

Comments
 (0)