Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

snp quic #20

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1b02d30
snp quic
turuslan Feb 11, 2025
f67cf4e
ci
turuslan Feb 11, 2025
ed8eb71
ci
turuslan Feb 11, 2025
f7cf132
snp quic + rebase
turuslan Feb 12, 2025
8444b77
merge rebase
turuslan Feb 12, 2025
bffc90b
forward
turuslan Feb 17, 2025
e499d39
make_shared
turuslan Feb 17, 2025
95699a2
move
turuslan Feb 17, 2025
89f987b
weak
turuslan Feb 17, 2025
0c9f159
set coro thread
turuslan Feb 17, 2025
f742c39
coro yield
turuslan Feb 17, 2025
e814063
enum type
turuslan Feb 17, 2025
bbddad4
cppcodec macro
turuslan Feb 17, 2025
b12bdcd
numeric limits
turuslan Feb 17, 2025
856d7f4
if return
turuslan Feb 17, 2025
5bb57a4
likely
turuslan Feb 17, 2025
b853b9a
self from void
turuslan Feb 17, 2025
22699ad
example
turuslan Feb 17, 2025
ef17c47
sizeof
turuslan Feb 17, 2025
9814d46
rename
turuslan Feb 17, 2025
387193e
rename self
turuslan Feb 17, 2025
0bfb4fd
error text
turuslan Feb 17, 2025
b9d83cc
comment
turuslan Feb 17, 2025
90b06ab
comment
turuslan Feb 17, 2025
a34d339
comment
turuslan Feb 17, 2025
25c3e6d
variant get
turuslan Feb 17, 2025
6aa4b49
hash constraint
turuslan Feb 18, 2025
ad703ed
forward
turuslan Feb 18, 2025
749ee00
comment
turuslan Feb 18, 2025
34c487a
executor constraint
turuslan Feb 18, 2025
8e9d06e
optional
turuslan Feb 18, 2025
4c9e48b
revert optional
turuslan Feb 25, 2025
f5b2466
update qtils
turuslan Feb 26, 2025
927632c
soralog
turuslan Feb 26, 2025
e97ecc8
if
turuslan Feb 26, 2025
4572529
make shared
turuslan Feb 27, 2025
bb881b5
revert "make shared"
turuslan Feb 27, 2025
812e33f
port type
turuslan Mar 3, 2025
2eaf302
shutdown
turuslan Mar 3, 2025
5632697
remove
turuslan Mar 3, 2025
790ce87
log socket read/write error
turuslan Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .ci/.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ LINUX_PACKAGES="make \
curl \
git \
libtool \
nasm \
ninja-build \
pkg-config \
python3.12 \
Expand All @@ -22,7 +23,9 @@ MACOS_PACKAGES="make \
rust \
curl \
git \
go \
libtool \
nasm \
ninja \
pkg-config \
[email protected] \
Expand Down
4 changes: 4 additions & 0 deletions BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

```bash
brew install nasm # vcpkg liblsquic
```
27 changes: 17 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ if (TESTING)
list(APPEND VCPKG_MANIFEST_FEATURES test)
endif ()

option(BUILD_EXAMPLES "Build examples" ON)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
Expand All @@ -30,21 +32,22 @@ find_package(PkgConfig REQUIRED)
pkg_check_modules(libb2 REQUIRED IMPORTED_TARGET GLOBAL libb2)

find_package(Boost CONFIG REQUIRED COMPONENTS algorithm outcome program_options)
find_package(Boost.DI CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(yaml-cpp CONFIG REQUIRED)
find_package(jam_crust CONFIG REQUIRED)
find_package(lsquic CONFIG REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(prometheus-cpp CONFIG REQUIRED)
find_package(qtils CONFIG REQUIRED)
find_package(scale CONFIG REQUIRED)
find_package(soralog CONFIG REQUIRED)
find_package(schnorrkel_crust CONFIG REQUIRED)
find_package(Boost.DI CONFIG REQUIRED)
find_package(qtils CONFIG REQUIRED)
find_package(prometheus-cpp CONFIG REQUIRED)
find_package(soralog CONFIG REQUIRED)
find_package(yaml-cpp CONFIG REQUIRED)
find_package(ZLIB REQUIRED)

add_library(headers INTERFACE)
target_include_directories(headers INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src_>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
include(vcpkg-overlay/cppcodec.cmake)

include_directories(${CMAKE_SOURCE_DIR}/src)

add_subdirectory(src)

Expand All @@ -57,3 +60,7 @@ if (TESTING)
add_subdirectory(test-vectors)
add_subdirectory(tests)
endif ()

if (BUILD_EXAMPLES)
add_subdirectory(example)
endif ()
7 changes: 7 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#
# Copyright Quadrivium LLC
# All Rights Reserved
# SPDX-License-Identifier: Apache-2.0
#

add_subdirectory(snp_chat)
7 changes: 4 additions & 3 deletions example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ logging:
children:
- name: jam
children:
- name: injector
- name: application
- name: rpc
- name: injector
- name: metrics
- name: threads
- name: rpc
- name: snp
- name: threads
14 changes: 14 additions & 0 deletions example/snp_chat/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
# Copyright Quadrivium LLC
# All Rights Reserved
# SPDX-License-Identifier: Apache-2.0
#

add_executable(example_snp_chat
main.cpp
)
target_link_libraries(example_snp_chat
logger
snp
)

244 changes: 244 additions & 0 deletions example/snp_chat/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#include <TODO_qtils/asio_buffer.hpp>
#include <boost/asio/as_tuple.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/outcome/try.hpp>
#include <fmt/format.h>
#include <qtils/append.hpp>
#include <qtils/unhex.hpp>

#include "coro/spawn.hpp"
#include "log/simple.hpp"
#include "snp/connections/address.hpp"
#include "snp/connections/connection.hpp"
#include "snp/connections/connections.hpp"
#include "snp/connections/controller.hpp"
#include "snp/connections/stream.hpp"

using jam::Coro;
using jam::coroHandler;
using jam::CoroHandler;
using jam::CoroOutcome;
using jam::coroSpawn;
using jam::GenesisHash;
using jam::IoContextPtr;
using jam::crypto::ed25519::KeyPair;
using jam::snp::Address;
using jam::snp::ConnectionInfo;
using jam::snp::Connections;
using jam::snp::ConnectionsConfig;
using jam::snp::ConnectionsController;
using jam::snp::Key;
using jam::snp::ProtocolId;
using jam::snp::StreamPtr;

auto logsys = jam::log::simpleLoggingSystem();

inline auto operator""_ed25519(const char *c, size_t s) {
auto seed = qtils::unhex<jam::crypto::ed25519::Seed>({c, s}).value();
return jam::crypto::ed25519::from_seed(seed);
}

std::vector<KeyPair> keys{
"f8dfdb0f1103d9fb2905204ac32529d5f148761c4321b2865b0a40e15be75f57"_ed25519,
"96c891b8726cb18c781aefc082dbafcb827e16c8f18f22d461e83eabd618e780"_ed25519,
"619d5e68139f714ee8e7892ce5afd8fbe7a4172a675fea5c5a06fb94fe3d797d"_ed25519,
"8d0c5f498a763eaa8c04861cac06289784140b4bbfa814fef898f1f4095de4a3"_ed25519,
};
Address server_address{
Address::kLocal,
10000,
jam::crypto::ed25519::get_public(keys[0]),
};
ProtocolId protocol_id = ProtocolId::make(0, true).value();

size_t indexOfKey(const Key &key) {
auto it = std::ranges::find_if(keys, [&](const KeyPair &keypair) {
return jam::crypto::ed25519::get_public(keypair) == key;
});
if (it == keys.end()) {
throw std::logic_error{"TODO: example"};
}
return it - keys.begin();
}

struct ChatController : ConnectionsController {
static constexpr size_t kMaxMsg = 8;

struct Writer {
StreamPtr stream;
std::deque<qtils::Bytes> queue;
bool writing = false;
};
using WriterPtr = std::shared_ptr<Writer>;

std::map<size_t, WriterPtr> writers;

static CoroOutcome<void> write(WriterPtr writer,
size_t i_msg,
const std::string msg) {
qtils::Bytes buffer;
buffer.emplace_back(i_msg);
qtils::append(buffer, qtils::str2byte(msg));
writer->queue.emplace_back(buffer);
if (writer->writing) {
co_return outcome::success();
}
writer->writing = true;
while (not writer->queue.empty()) {
auto buffer = writer->queue.front();
writer->queue.pop_front();
BOOST_OUTCOME_CO_TRY(
co_await writer->stream->write(writer->stream, buffer));
}
writer->writing = false;
co_return outcome::success();
}

void onOpen(Key key) override {
fmt::println("#{} (connected)", indexOfKey(key));
}

void onClose(Key key) override {
fmt::println("#{} (disconnected)", indexOfKey(key));
}

void print(size_t i_msg, std::string msg) {
fmt::println("#{} > {}", i_msg, msg);
}

Coro<void> broadcast(std::optional<size_t> i_read,
size_t i_msg,
std::string msg) {
for (auto &[i_write, writer] : writers) {
if (i_write == i_read) {
continue;
}
co_await coroSpawn([this, i_write, writer, i_msg, msg]() -> Coro<void> {
if (not co_await write(writer, i_msg, msg)) {
writers.erase(i_write);
}
});
}
}

Coro<void> onRead(size_t i_read, size_t i_msg, std::string msg) {
print(i_msg, msg);
co_await broadcast(i_read, i_msg, msg);
}

CoroOutcome<void> add(ConnectionInfo info, StreamPtr stream) {
auto i_read = indexOfKey(info.key);
writers.emplace(i_read, std::make_shared<Writer>(Writer{stream}));
qtils::Bytes buffer;
while (true) {
BOOST_OUTCOME_CO_TRY(auto read,
co_await stream->read(stream, buffer, 1 + kMaxMsg));
if (not read) {
break;
}
if (buffer.size() < 1) {
break;
}
auto i_msg = buffer[0];
co_await onRead(
i_read, i_msg, std::string{qtils::byte2str(buffer).substr(1)});
}
co_await stream->shutdownRead(stream);
co_return outcome::success();
}
};

struct Input {
Input(IoContextPtr io_context_ptr) : fd_{*io_context_ptr, STDIN_FILENO} {}

Coro<std::optional<std::string>> read() {
auto [ec, n] = co_await boost::asio::async_read_until(
fd_, buf_, "\n", boost::asio::as_tuple(boost::asio::use_awaitable));
if (ec) {
co_return std::nullopt;
}
auto s = qtils::byte2str(qtils::asioBuffer(buf_.data()));
auto i = s.find("\n");
if (i != s.npos) {
s = s.substr(0, i);
}
auto r = std::string{s};
buf_.consume(buf_.size());
co_return r;
}

boost::asio::posix::stream_descriptor fd_;
boost::asio::streambuf buf_;
};

CoroOutcome<void> co_main(IoContextPtr io_context_ptr, size_t arg_i) {
fmt::println("#{} (self)", arg_i);

std::optional<uint16_t> listen_port;
GenesisHash genesis;
ConnectionsConfig config{genesis, keys.at(arg_i)};
auto is_server = arg_i == 0;
if (is_server) {
config.listen_port = server_address.port;
}
auto connections =
std::make_shared<Connections>(io_context_ptr, logsys, config);
auto chat = std::make_shared<ChatController>();
BOOST_OUTCOME_CO_TRY(co_await connections->init(connections, chat));
co_await coroSpawn([io_context_ptr, arg_i, chat]() -> Coro<void> {
Input input{io_context_ptr};
while (true) {
auto msg = co_await input.read();
if (not msg.has_value()) {
break;
}
msg->resize(std::min(msg->size(), ChatController::kMaxMsg));
if (msg->empty()) {
continue;
}
co_await chat->broadcast(std::nullopt, arg_i, *msg);
}
io_context_ptr->stop();
});
if (not is_server) {
BOOST_OUTCOME_CO_TRY(
auto connection,
co_await connections->connect(connections, server_address));
BOOST_OUTCOME_CO_TRY(auto stream,
co_await connection->open(connection, protocol_id));
std::ignore = co_await chat->add(connection->info(), stream);
fmt::println("(disconnected)");
io_context_ptr->stop();
} else {
co_await connections->serve(
connections,
protocol_id,
[chat](ConnectionInfo info, StreamPtr stream) -> CoroOutcome<void> {
co_return co_await chat->add(info, stream);
});
std::optional<CoroHandler<void>> work_guard;
co_await coroHandler<void>([&](CoroHandler<void> &&handler) {
work_guard.emplace(std::move(handler));
});
}
co_return outcome::success();
}

int main(int argc, char **argv) {
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);

size_t arg_i = 0;
if (argc == 2) {
arg_i = std::atoi(argv[1]);
}

auto io_context_ptr = std::make_shared<boost::asio::io_context>();
coroSpawn(*io_context_ptr, [io_context_ptr, arg_i]() -> Coro<void> {
(co_await co_main(io_context_ptr, arg_i)).value();
});
io_context_ptr->run();
}
5 changes: 3 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
# SPDX-License-Identifier: Apache-2.0
#

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

# Executables (should contain `main()` function)
add_subdirectory(executable)

Expand All @@ -24,3 +22,6 @@ add_subdirectory(metrics)
# Clocks and time subsystem
add_subdirectory(clock)

# Simple Network Protocol
add_subdirectory(snp)

Loading
Loading