mirror of
https://github.com/logos-blockchain/logos-blockchain-module.git
synced 2026-08-04 05:13:13 +00:00
Compare commits
No commits in common. "master" and "v0.0.3" have entirely different histories.
@ -9,7 +9,7 @@ endif()
|
|||||||
|
|
||||||
# Universal module — generated_code/ is picked up automatically by LogosModule.cmake
|
# Universal module — generated_code/ is picked up automatically by LogosModule.cmake
|
||||||
logos_module(
|
logos_module(
|
||||||
NAME blockchain_module
|
NAME liblogos_blockchain_module
|
||||||
SOURCES
|
SOURCES
|
||||||
src/logos_blockchain_module.h
|
src/logos_blockchain_module.h
|
||||||
src/logos_blockchain_module.cpp
|
src/logos_blockchain_module.cpp
|
||||||
|
|||||||
14030
flake.lock
generated
14030
flake.lock
generated
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,9 @@
|
|||||||
description = "Logos Blockchain Module - Qt6 Plugin";
|
description = "Logos Blockchain Module - Qt6 Plugin";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
logos-module-builder.url = "github:logos-co/logos-module-builder/0.2.4";
|
logos-module-builder.url = "github:logos-co/logos-module-builder?ref=38ddf92c1f240f4e420d300a1fbabb1609d5db01";
|
||||||
logos-blockchain.url = "github:logos-blockchain/logos-blockchain?ref=133570d58a141629a0c751fdf4412a66898acac2";
|
# https://github.com/logos-blockchain/logos-blockchain/commit/58d71393cb7c5e8d425f54b09f2f28e0d9905fdc
|
||||||
|
logos-blockchain.url = "github:logos-blockchain/logos-blockchain?ref=58d71393cb7c5e8d425f54b09f2f28e0d9905fdc";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs@{ logos-module-builder, ... }:
|
outputs = inputs@{ logos-module-builder, ... }:
|
||||||
|
|||||||
2
justfile
2
justfile
@ -7,7 +7,7 @@ configure:
|
|||||||
cmake -S . -B build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
cmake -S . -B build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
|
||||||
build: configure
|
build: configure
|
||||||
cmake --build build --parallel --target blockchain_module_module_plugin
|
cmake --build build --parallel --target liblogos_blockchain_module_module_plugin
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf build result
|
rm -rf build result
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "blockchain_module",
|
"name": "liblogos_blockchain_module",
|
||||||
"display_name": "Blockchain Module",
|
"display_name": "Blockchain Module",
|
||||||
"version": "0.0.999",
|
"version": "1.0.0",
|
||||||
"description": "Logos blockchain node for logos-core",
|
"description": "Logos blockchain node for logos-core",
|
||||||
"author": "Logos Blockchain Team",
|
"author": "Logos Blockchain Team",
|
||||||
"type": "core",
|
"type": "core",
|
||||||
@ -11,16 +11,16 @@
|
|||||||
"impl_class": "LogosBlockchainModule"
|
"impl_class": "LogosBlockchainModule"
|
||||||
},
|
},
|
||||||
"category": "blockchain",
|
"category": "blockchain",
|
||||||
"main": "blockchain_module_plugin",
|
"main": "liblogos_blockchain_module_plugin",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"capabilities": [],
|
"capabilities": [],
|
||||||
"include": [
|
"include": [
|
||||||
"liblogos_blockchain.dylib",
|
"liblogos_blockchain.dylib",
|
||||||
"liblogos_blockchain.so",
|
"liblogos_blockchain.so",
|
||||||
"liblogos_blockchain.dll",
|
"liblogos_blockchain.dll",
|
||||||
"blockchain_module_plugin.dylib",
|
"liblogos_blockchain_module_plugin.dylib",
|
||||||
"blockchain_module_plugin.so",
|
"liblogos_blockchain_module_plugin.so",
|
||||||
"blockchain_module_plugin.dll"
|
"liblogos_blockchain_module_plugin.dll"
|
||||||
],
|
],
|
||||||
|
|
||||||
"nix": {
|
"nix": {
|
||||||
|
|||||||
@ -17,19 +17,6 @@ using json = nlohmann::json;
|
|||||||
// Define static member
|
// Define static member
|
||||||
LogosBlockchainModule* LogosBlockchainModule::s_instance = nullptr;
|
LogosBlockchainModule* LogosBlockchainModule::s_instance = nullptr;
|
||||||
|
|
||||||
namespace operation_status {
|
|
||||||
// Takes the Rust-allocated message out of an OperationStatus and frees it.
|
|
||||||
std::string take_message(OperationStatus& status) {
|
|
||||||
std::string message;
|
|
||||||
if (status.message) {
|
|
||||||
message = status.message;
|
|
||||||
(void)free_cstring(status.message);
|
|
||||||
status.message = nullptr;
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
} // namespace operation_status
|
|
||||||
|
|
||||||
// Shorthands for building StdLogosResult values.
|
// Shorthands for building StdLogosResult values.
|
||||||
namespace result {
|
namespace result {
|
||||||
StdLogosResult ok() {
|
StdLogosResult ok() {
|
||||||
@ -44,13 +31,6 @@ namespace result {
|
|||||||
StdLogosResult err(std::string message) {
|
StdLogosResult err(std::string message) {
|
||||||
return {false, {}, std::move(message)};
|
return {false, {}, std::move(message)};
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult from_operation_status(OperationStatus& status) {
|
|
||||||
if (is_ok(&status)) {
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
return err(operation_status::take_message(status));
|
|
||||||
}
|
|
||||||
} // namespace result
|
} // namespace result
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -144,7 +124,7 @@ namespace {
|
|||||||
std::string state_path_data;
|
std::string state_path_data;
|
||||||
std::string storage_path_data;
|
std::string storage_path_data;
|
||||||
std::string logs_path_data;
|
std::string logs_path_data;
|
||||||
bool skip_ibd_val;
|
bool ibd_val;
|
||||||
std::string log_filter_data;
|
std::string log_filter_data;
|
||||||
std::string kms_file_data;
|
std::string kms_file_data;
|
||||||
|
|
||||||
@ -235,12 +215,12 @@ namespace {
|
|||||||
ffi_args.logs_path = nullptr;
|
ffi_args.logs_path = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip_ibd (bool -> const bool*)
|
// ibd (bool -> const bool*)
|
||||||
if (args.contains("skip_ibd") && args["skip_ibd"].is_boolean()) {
|
if (args.contains("ibd") && args["ibd"].is_boolean()) {
|
||||||
skip_ibd_val = args["skip_ibd"].get<bool>();
|
ibd_val = args["ibd"].get<bool>();
|
||||||
ffi_args.skip_ibd = &skip_ibd_val;
|
ffi_args.ibd = &ibd_val;
|
||||||
} else {
|
} else {
|
||||||
ffi_args.skip_ibd = nullptr;
|
ffi_args.ibd = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// log_filter (string -> const char*)
|
// log_filter (string -> const char*)
|
||||||
@ -263,45 +243,15 @@ namespace {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void LogosBlockchainModule::on_new_block_callback(const char* block) {
|
void LogosBlockchainModule::on_new_block_callback(const char* block) {
|
||||||
if (!s_instance || !block) {
|
if (s_instance) {
|
||||||
return;
|
fprintf(stderr, "Received new block: %s\n", block);
|
||||||
|
json j;
|
||||||
|
j["block"] = std::string(block);
|
||||||
|
s_instance->newBlock(j.dump());
|
||||||
|
// SAFETY:
|
||||||
|
// We are getting an owned pointer here which is freed after this callback is called, so there is no need to
|
||||||
|
// free the resource here as we are copying the data!
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Received new block: %s\n", block);
|
|
||||||
json j;
|
|
||||||
j["block"] = std::string(block);
|
|
||||||
s_instance->newBlock(j.dump());
|
|
||||||
// SAFETY:
|
|
||||||
// We are getting an owned pointer here which is freed after this callback is called, so there is no need to
|
|
||||||
// free the resource here as we are copying the data!
|
|
||||||
}
|
|
||||||
|
|
||||||
// The stream callbacks pass the FFI's JSON through unwrapped (it is already a
|
|
||||||
// complete JSON document with the node's HTTP stream schema). A NULL pointer
|
|
||||||
// means the stream ended; it is forwarded as the JSON literal `null` so
|
|
||||||
// termination stays in-band on the same event.
|
|
||||||
|
|
||||||
void LogosBlockchainModule::on_processed_block_callback(const char* event) {
|
|
||||||
if (!s_instance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!event) {
|
|
||||||
fprintf(stderr, "Processed block stream ended.\n");
|
|
||||||
s_instance->processedBlock("null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_instance->processedBlock(std::string(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogosBlockchainModule::on_lib_block_callback(const char* event) {
|
|
||||||
if (!s_instance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!event) {
|
|
||||||
fprintf(stderr, "LIB block stream ended.\n");
|
|
||||||
s_instance->libBlock("null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_instance->libBlock(std::string(event));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogosBlockchainModule::LogosBlockchainModule() {
|
LogosBlockchainModule::LogosBlockchainModule() {
|
||||||
@ -319,7 +269,7 @@ LogosBlockchainModule::~LogosBlockchainModule() {
|
|||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& json_args) const {
|
StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& json_args) {
|
||||||
json parsed_args;
|
json parsed_args;
|
||||||
try {
|
try {
|
||||||
parsed_args = json::parse(json_args);
|
parsed_args = json::parse(json_args);
|
||||||
@ -337,7 +287,8 @@ StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& js
|
|||||||
// standalone callers omit the flag and keep their own paths (or the node
|
// standalone callers omit the flag and keep their own paths (or the node
|
||||||
// defaults). Any path the caller set explicitly is left untouched.
|
// defaults). Any path the caller set explicitly is left untouched.
|
||||||
bool use_persistence_paths = false;
|
bool use_persistence_paths = false;
|
||||||
if (const auto it = parsed_args.find("use_persistence_paths"); it != parsed_args.end() && it->is_boolean()) {
|
if (const auto it = parsed_args.find("use_persistence_paths");
|
||||||
|
it != parsed_args.end() && it->is_boolean()) {
|
||||||
use_persistence_paths = it->get<bool>();
|
use_persistence_paths = it->get<bool>();
|
||||||
}
|
}
|
||||||
parsed_args.erase("use_persistence_paths"); // not an FFI field
|
parsed_args.erase("use_persistence_paths"); // not an FFI field
|
||||||
@ -348,8 +299,9 @@ StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& js
|
|||||||
const fs::path base(persistence);
|
const fs::path base(persistence);
|
||||||
// Only fill a path the caller didn't pin (non-empty string wins).
|
// Only fill a path the caller didn't pin (non-empty string wins).
|
||||||
const auto set_if_absent = [&parsed_args](const char* key, const std::string& value) {
|
const auto set_if_absent = [&parsed_args](const char* key, const std::string& value) {
|
||||||
const bool provided = parsed_args.contains(key) && parsed_args[key].is_string() &&
|
const bool provided = parsed_args.contains(key)
|
||||||
!parsed_args[key].get<std::string>().empty();
|
&& parsed_args[key].is_string()
|
||||||
|
&& !parsed_args[key].get<std::string>().empty();
|
||||||
if (!provided)
|
if (!provided)
|
||||||
parsed_args[key] = value;
|
parsed_args[key] = value;
|
||||||
};
|
};
|
||||||
@ -364,8 +316,8 @@ StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& js
|
|||||||
// as relative to the base; a missing output defaults to
|
// as relative to the base; a missing output defaults to
|
||||||
// "<base>/user_config.yaml".
|
// "<base>/user_config.yaml".
|
||||||
fs::path output_rel = "user_config.yaml";
|
fs::path output_rel = "user_config.yaml";
|
||||||
if (parsed_args.contains("output") && parsed_args["output"].is_string() &&
|
if (parsed_args.contains("output") && parsed_args["output"].is_string()
|
||||||
!parsed_args["output"].get<std::string>().empty()) {
|
&& !parsed_args["output"].get<std::string>().empty()) {
|
||||||
const fs::path given(localPathFromFileUrl(parsed_args["output"].get<std::string>()));
|
const fs::path given(localPathFromFileUrl(parsed_args["output"].get<std::string>()));
|
||||||
const fs::path rel = given.relative_path();
|
const fs::path rel = given.relative_path();
|
||||||
output_rel = rel.empty() ? given.filename() : rel;
|
output_rel = rel.empty() ? given.filename() : rel;
|
||||||
@ -382,8 +334,7 @@ StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& js
|
|||||||
} else {
|
} else {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"generate_user_config: use_persistence_paths requested but no instance persistence path is set; "
|
"generate_user_config: use_persistence_paths requested but no instance persistence path is set; leaving paths unchanged.\n"
|
||||||
"leaving paths unchanged.\n"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,9 +349,10 @@ StdLogosResult LogosBlockchainModule::generate_user_config(const std::string& js
|
|||||||
|
|
||||||
const OwnedGenerateConfigArgs owned_args(parsed_args);
|
const OwnedGenerateConfigArgs owned_args(parsed_args);
|
||||||
|
|
||||||
OperationStatus status = ::generate_user_config(owned_args.ffi_args);
|
const OperationStatus status = ::generate_user_config(owned_args.ffi_args);
|
||||||
if (!is_ok(&status)) {
|
if (!is_ok(&status)) {
|
||||||
return result::err(operation_status::take_message(status));
|
fprintf(stderr, "Failed to generate user config. Error: %d\n", status);
|
||||||
|
return result::err("Failed to generate user config.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result::ok(resolved_output);
|
return result::ok(resolved_output);
|
||||||
@ -432,27 +384,28 @@ StdLogosResult LogosBlockchainModule::start(const std::string& config_path, cons
|
|||||||
const char* deployment_ptr = deployment_path.empty() ? nullptr : deployment_path.c_str();
|
const char* deployment_ptr = deployment_path.empty() ? nullptr : deployment_path.c_str();
|
||||||
|
|
||||||
auto [value, error] = start_lb_node(config_path_ptr, deployment_ptr);
|
auto [value, error] = start_lb_node(config_path_ptr, deployment_ptr);
|
||||||
|
fprintf(stderr, "Start node returned with value and error.\n");
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to start the node. Error: %d\n", error);
|
||||||
|
return result::err("Failed to start the node.");
|
||||||
}
|
}
|
||||||
|
|
||||||
node = value;
|
node = value;
|
||||||
|
fprintf(stderr, "The node was started successfully.\n");
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
fprintf(stderr, "Could not subscribe to block events: The node is not running.\n");
|
||||||
return result::err("Could not subscribe to block events: the node is not running.");
|
return result::err("Could not subscribe to block events: the node is not running.");
|
||||||
}
|
}
|
||||||
|
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
OperationStatus subscribe_status = subscribe_to_new_blocks(node, on_new_block_callback);
|
const OperationStatus subscribe_status = subscribe_to_new_blocks(node, on_new_block_callback);
|
||||||
if (!is_ok(&subscribe_status)) {
|
if (!is_ok(&subscribe_status)) {
|
||||||
return result::err(operation_status::take_message(subscribe_status));
|
fprintf(stderr, "Failed to subscribe to new blocks. Error: %d\n", subscribe_status);
|
||||||
|
return result::err("Failed to subscribe to new blocks.");
|
||||||
}
|
}
|
||||||
OperationStatus processed_status = subscribe_to_processed_blocks(node, on_processed_block_callback);
|
|
||||||
if (!is_ok(&processed_status)) {
|
return result::ok();
|
||||||
return result::err(operation_status::take_message(processed_status));
|
|
||||||
}
|
|
||||||
OperationStatus lib_status = subscribe_to_lib_blocks(node, on_lib_block_callback);
|
|
||||||
return result::from_operation_status(lib_status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::stop() {
|
StdLogosResult LogosBlockchainModule::stop() {
|
||||||
@ -463,9 +416,11 @@ StdLogosResult LogosBlockchainModule::stop() {
|
|||||||
|
|
||||||
s_instance = nullptr;
|
s_instance = nullptr;
|
||||||
|
|
||||||
OperationStatus status = shutdown_node(node);
|
const OperationStatus status = stop_node(node);
|
||||||
if (!is_ok(&status)) {
|
if (is_ok(&status)) {
|
||||||
fprintf(stderr, "Could not stop the node: %s\n", operation_status::take_message(status).c_str());
|
fprintf(stderr, "The node was stopped successfully.\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Could not stop the node. Error: %d\n", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
node = nullptr;
|
node = nullptr;
|
||||||
@ -481,8 +436,12 @@ StdLogosResult LogosBlockchainModule::update_user_config(
|
|||||||
const std::string config = localPathFromFileUrl(user_config_path);
|
const std::string config = localPathFromFileUrl(user_config_path);
|
||||||
const std::string keystore = localPathFromFileUrl(keystore_path);
|
const std::string keystore = localPathFromFileUrl(keystore_path);
|
||||||
|
|
||||||
OperationStatus status = ::update_user_config(config.c_str(), keystore.c_str());
|
const OperationStatus status = ::update_user_config(config.c_str(), keystore.c_str());
|
||||||
return result::from_operation_status(status);
|
if (!is_ok(&status)) {
|
||||||
|
fprintf(stderr, "Failed to update user config. Error: %d\n", status);
|
||||||
|
return result::err("Failed to update user config.");
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::migrate_user_config(
|
StdLogosResult LogosBlockchainModule::migrate_user_config(
|
||||||
@ -492,8 +451,12 @@ StdLogosResult LogosBlockchainModule::migrate_user_config(
|
|||||||
const std::string output = localPathFromFileUrl(output_path);
|
const std::string output = localPathFromFileUrl(output_path);
|
||||||
const std::string keystore = localPathFromFileUrl(keystore_path);
|
const std::string keystore = localPathFromFileUrl(keystore_path);
|
||||||
|
|
||||||
OperationStatus status = ::migrate_user_config(output.c_str(), keystore.c_str());
|
const OperationStatus status = ::migrate_user_config(output.c_str(), keystore.c_str());
|
||||||
return result::from_operation_status(status);
|
if (!is_ok(&status)) {
|
||||||
|
fprintf(stderr, "Failed to migrate user config. Error: %d\n", status);
|
||||||
|
return result::err("Failed to migrate user config.");
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::migrate_user_config_0_1_2(
|
StdLogosResult LogosBlockchainModule::migrate_user_config_0_1_2(
|
||||||
@ -505,8 +468,13 @@ StdLogosResult LogosBlockchainModule::migrate_user_config_0_1_2(
|
|||||||
const std::string old_config = localPathFromFileUrl(old_config_path);
|
const std::string old_config = localPathFromFileUrl(old_config_path);
|
||||||
const std::string keystore = localPathFromFileUrl(keystore_path);
|
const std::string keystore = localPathFromFileUrl(keystore_path);
|
||||||
|
|
||||||
OperationStatus status = ::migrate_user_config_0_1_2(new_config.c_str(), old_config.c_str(), keystore.c_str());
|
const OperationStatus status =
|
||||||
return result::from_operation_status(status);
|
::migrate_user_config_0_1_2(new_config.c_str(), old_config.c_str(), keystore.c_str());
|
||||||
|
if (!is_ok(&status)) {
|
||||||
|
fprintf(stderr, "Failed to migrate 0.1.2 config. Error: %d\n", status);
|
||||||
|
return result::err("Failed to migrate 0.1.2 config.");
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::participate(
|
StdLogosResult LogosBlockchainModule::participate(
|
||||||
@ -520,8 +488,13 @@ StdLogosResult LogosBlockchainModule::participate(
|
|||||||
const std::string output = localPathFromFileUrl(output_dir);
|
const std::string output = localPathFromFileUrl(output_dir);
|
||||||
const char* external_address_ptr = external_address.empty() ? nullptr : external_address.c_str();
|
const char* external_address_ptr = external_address.empty() ? nullptr : external_address.c_str();
|
||||||
|
|
||||||
OperationStatus status = ::participate(config.c_str(), keystore.c_str(), output.c_str(), external_address_ptr);
|
const OperationStatus status =
|
||||||
return result::from_operation_status(status);
|
::participate(config.c_str(), keystore.c_str(), output.c_str(), external_address_ptr);
|
||||||
|
if (!is_ok(&status)) {
|
||||||
|
fprintf(stderr, "Failed to generate participation data. Error: %d\n", status);
|
||||||
|
return result::err("Failed to generate participation data.");
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keystore
|
// Keystore
|
||||||
@ -543,13 +516,14 @@ StdLogosResult LogosBlockchainModule::generate_key(
|
|||||||
|
|
||||||
auto [value, error] = ::generate_key(config.c_str(), keystore.c_str(), type, key_title_ptr);
|
auto [value, error] = ::generate_key(config.c_str(), keystore.c_str(), type, key_title_ptr);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to generate key. Error: %d\n", error);
|
||||||
|
return result::err("Failed to generate key: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string out(value);
|
const std::string out(value);
|
||||||
OperationStatus free_status = free_cstring(value);
|
const OperationStatus free_status = free_cstring(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free key id string: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free key id string. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
return result::ok(out);
|
return result::ok(out);
|
||||||
}
|
}
|
||||||
@ -571,8 +545,12 @@ StdLogosResult LogosBlockchainModule::add_key(
|
|||||||
const std::string keystore = localPathFromFileUrl(keystore_path);
|
const std::string keystore = localPathFromFileUrl(keystore_path);
|
||||||
const char* key_title_ptr = key_title.empty() ? nullptr : key_title.c_str();
|
const char* key_title_ptr = key_title.empty() ? nullptr : key_title.c_str();
|
||||||
|
|
||||||
OperationStatus status = ::add_key(config.c_str(), keystore.c_str(), type, key_hex.c_str(), key_title_ptr);
|
const OperationStatus status = ::add_key(config.c_str(), keystore.c_str(), type, key_hex.c_str(), key_title_ptr);
|
||||||
return result::from_operation_status(status);
|
if (!is_ok(&status)) {
|
||||||
|
fprintf(stderr, "Failed to add key. Error: %d\n", status);
|
||||||
|
return result::err("Failed to add key.");
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::remove_key(
|
StdLogosResult LogosBlockchainModule::remove_key(
|
||||||
@ -583,8 +561,12 @@ StdLogosResult LogosBlockchainModule::remove_key(
|
|||||||
const std::string config = localPathFromFileUrl(user_config_path);
|
const std::string config = localPathFromFileUrl(user_config_path);
|
||||||
const std::string keystore = localPathFromFileUrl(keystore_path);
|
const std::string keystore = localPathFromFileUrl(keystore_path);
|
||||||
|
|
||||||
OperationStatus status = ::remove_key(config.c_str(), keystore.c_str(), key_title.c_str());
|
const OperationStatus status = ::remove_key(config.c_str(), keystore.c_str(), key_title.c_str());
|
||||||
return result::from_operation_status(status);
|
if (!is_ok(&status)) {
|
||||||
|
fprintf(stderr, "Failed to remove key. Error: %d\n", status);
|
||||||
|
return result::err("Failed to remove key.");
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identity
|
// Identity
|
||||||
@ -594,13 +576,14 @@ StdLogosResult LogosBlockchainModule::get_peer_id(const std::string& config_path
|
|||||||
|
|
||||||
auto [value, error] = ::get_peer_id(config.c_str());
|
auto [value, error] = ::get_peer_id(config.c_str());
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to get peer id. Error: %d\n", error);
|
||||||
|
return result::err("Failed to get peer id: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string out(value);
|
const std::string out(value);
|
||||||
OperationStatus free_status = free_cstring(value);
|
const OperationStatus free_status = free_cstring(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free peer id string: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free peer id string. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
return result::ok(out);
|
return result::ok(out);
|
||||||
}
|
}
|
||||||
@ -620,7 +603,7 @@ StdLogosResult LogosBlockchainModule::wallet_get_balance(const std::string& addr
|
|||||||
|
|
||||||
auto [value, error] = get_balance(node, bytes.data(), nullptr);
|
auto [value, error] = get_balance(node, bytes.data(), nullptr);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to get balance: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result::ok(std::to_string(value));
|
return result::ok(std::to_string(value));
|
||||||
@ -688,7 +671,7 @@ StdLogosResult LogosBlockchainModule::wallet_transfer_funds(
|
|||||||
|
|
||||||
auto [value, error] = transfer_funds(node, &args);
|
auto [value, error] = transfer_funds(node, &args);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to transfer funds: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), ADDRESS_BYTES));
|
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), ADDRESS_BYTES));
|
||||||
}
|
}
|
||||||
@ -700,7 +683,8 @@ StdLogosResult LogosBlockchainModule::wallet_get_known_addresses() const {
|
|||||||
}
|
}
|
||||||
auto [value, error] = get_known_addresses(node);
|
auto [value, error] = get_known_addresses(node);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to get known addresses. Error: %d\n", error);
|
||||||
|
return result::err("Failed to get known addresses: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
std::vector<std::string> out;
|
std::vector<std::string> out;
|
||||||
for (size_t i = 0; i < value.len; ++i) {
|
for (size_t i = 0; i < value.len; ++i) {
|
||||||
@ -710,9 +694,9 @@ StdLogosResult LogosBlockchainModule::wallet_get_known_addresses() const {
|
|||||||
out.push_back(bytes_to_hex(ptr, ADDRESS_BYTES));
|
out.push_back(bytes_to_hex(ptr, ADDRESS_BYTES));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationStatus free_status = free_known_addresses(value);
|
const OperationStatus free_status = free_known_addresses(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free known addresses: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free known addresses. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
@ -748,7 +732,7 @@ StdLogosResult LogosBlockchainModule::wallet_get_notes(
|
|||||||
|
|
||||||
auto [value, error] = get_wallet_notes(node, address_bytes.data(), optional_tip);
|
auto [value, error] = get_wallet_notes(node, address_bytes.data(), optional_tip);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to get wallet notes: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
json obj;
|
json obj;
|
||||||
@ -764,9 +748,9 @@ StdLogosResult LogosBlockchainModule::wallet_get_notes(
|
|||||||
}
|
}
|
||||||
obj["notes"] = std::move(notes);
|
obj["notes"] = std::move(notes);
|
||||||
|
|
||||||
OperationStatus free_status = free_wallet_notes(value);
|
const OperationStatus free_status = free_wallet_notes(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free wallet notes: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free wallet notes. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
return result::ok(obj.dump());
|
return result::ok(obj.dump());
|
||||||
}
|
}
|
||||||
@ -778,7 +762,7 @@ StdLogosResult LogosBlockchainModule::leader_claim() const {
|
|||||||
|
|
||||||
auto [value, error] = ::leader_claim(node);
|
auto [value, error] = ::leader_claim(node);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to claim leader rewards: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), TX_HASH_BYTES));
|
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), TX_HASH_BYTES));
|
||||||
@ -843,7 +827,7 @@ StdLogosResult LogosBlockchainModule::channel_deposit(
|
|||||||
|
|
||||||
auto [value, error] = ::channel_deposit(node, &args);
|
auto [value, error] = ::channel_deposit(node, &args);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to deposit into channel: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), ADDRESS_BYTES));
|
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), ADDRESS_BYTES));
|
||||||
}
|
}
|
||||||
@ -939,36 +923,11 @@ StdLogosResult LogosBlockchainModule::channel_deposit_with_notes(
|
|||||||
|
|
||||||
auto [value, error] = ::channel_deposit_with_notes(node, &args);
|
auto [value, error] = ::channel_deposit_with_notes(node, &args);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to deposit into channel: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), ADDRESS_BYTES));
|
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), ADDRESS_BYTES));
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::get_channel_state(const std::string& channel_id_hex) const {
|
|
||||||
if (!node) {
|
|
||||||
return result::err("The node is not running.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<uint8_t> bytes = parse_address_hex(channel_id_hex);
|
|
||||||
if (bytes.empty() || static_cast<int>(bytes.size()) != ADDRESS_BYTES) {
|
|
||||||
return result::err("Invalid channel_id (64 hex characters required).");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto [value, error] = ::get_channel_state(node, bytes.data());
|
|
||||||
if (!is_ok(&error)) {
|
|
||||||
return result::err(operation_status::take_message(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string out(value);
|
|
||||||
OperationStatus free_status = free_cstring(value);
|
|
||||||
if (!is_ok(&free_status)) {
|
|
||||||
fprintf(
|
|
||||||
stderr, "Failed to free channel state string: %s\n", operation_status::take_message(free_status).c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return result::ok(std::move(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::wallet_get_claimable_vouchers() const {
|
StdLogosResult LogosBlockchainModule::wallet_get_claimable_vouchers() const {
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return result::err("The node is not running.");
|
return result::err("The node is not running.");
|
||||||
@ -976,7 +935,7 @@ StdLogosResult LogosBlockchainModule::wallet_get_claimable_vouchers() const {
|
|||||||
|
|
||||||
auto [value, error] = get_claimable_vouchers(node, nullptr);
|
auto [value, error] = get_claimable_vouchers(node, nullptr);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to get claimable vouchers: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
json obj;
|
json obj;
|
||||||
@ -991,58 +950,34 @@ StdLogosResult LogosBlockchainModule::wallet_get_claimable_vouchers() const {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus free_status = free_claimable_vouchers(value);
|
const OperationStatus free_status = free_claimable_vouchers(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free claimable vouchers: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free claimable vouchers. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result::ok(obj.dump());
|
return result::ok(obj.dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::wallet_fund_tx(const std::string& request_json) const {
|
|
||||||
if (!node) {
|
|
||||||
return result::err("The node is not running.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto [value, error] = ::wallet_fund_tx(node, request_json.c_str());
|
|
||||||
if (!is_ok(&error)) {
|
|
||||||
return result::err(operation_status::take_message(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string out(value);
|
|
||||||
OperationStatus free_status = free_cstring(value);
|
|
||||||
if (!is_ok(&free_status)) {
|
|
||||||
fprintf(stderr, "Failed to free funded tx string: %s\n", operation_status::take_message(free_status).c_str());
|
|
||||||
}
|
|
||||||
return result::ok(std::move(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transactions
|
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::submit_signed_transaction(const std::string& signed_tx_json) const {
|
|
||||||
if (!node) {
|
|
||||||
return result::err("The node is not running.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto [value, error] = ::submit_signed_transaction(node, signed_tx_json.c_str());
|
|
||||||
if (!is_ok(&error)) {
|
|
||||||
return result::err(operation_status::take_message(error));
|
|
||||||
}
|
|
||||||
return result::ok(bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), TX_HASH_BYTES));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blend
|
// Blend
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::blend_join_as_core_node(
|
StdLogosResult LogosBlockchainModule::blend_join_as_core_node(
|
||||||
const std::string& locator,
|
const std::string& provider_id_hex,
|
||||||
const std::string& locked_note_id_hex
|
const std::string& zk_id_hex,
|
||||||
|
const std::string& locked_note_id_hex,
|
||||||
|
const std::vector<std::string>& locators
|
||||||
) const {
|
) const {
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return result::err("The node is not running.");
|
return result::err("The node is not running.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locator.empty()) {
|
const std::vector<uint8_t> provider_id_bytes = parse_address_hex(provider_id_hex);
|
||||||
return result::err("Invalid locator (must not be empty).");
|
if (provider_id_bytes.empty() || static_cast<int>(provider_id_bytes.size()) != ADDRESS_BYTES) {
|
||||||
|
return result::err("Invalid provider_id_hex (64 hex characters required).");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<uint8_t> zk_id_bytes = parse_address_hex(zk_id_hex);
|
||||||
|
if (zk_id_bytes.empty() || static_cast<int>(zk_id_bytes.size()) != ADDRESS_BYTES) {
|
||||||
|
return result::err("Invalid zk_id_hex (64 hex characters required).");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<uint8_t> locked_note_id_bytes = parse_address_hex(locked_note_id_hex);
|
const std::vector<uint8_t> locked_note_id_bytes = parse_address_hex(locked_note_id_hex);
|
||||||
@ -1050,9 +985,23 @@ StdLogosResult LogosBlockchainModule::blend_join_as_core_node(
|
|||||||
return result::err("Invalid locked_note_id_hex (64 hex characters required).");
|
return result::err("Invalid locked_note_id_hex (64 hex characters required).");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [value, error] = ::blend_join_as_core_node(node, locator.c_str(), locked_note_id_bytes.data());
|
// locators_ptrs holds raw pointers into the std::strings (valid as long as `locators` lives).
|
||||||
|
std::vector<const char*> locators_ptrs;
|
||||||
|
locators_ptrs.reserve(locators.size());
|
||||||
|
for (const std::string& locator : locators) {
|
||||||
|
locators_ptrs.push_back(locator.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [value, error] = ::blend_join_as_core_node(
|
||||||
|
node,
|
||||||
|
provider_id_bytes.data(),
|
||||||
|
zk_id_bytes.data(),
|
||||||
|
locked_note_id_bytes.data(),
|
||||||
|
locators_ptrs.data(),
|
||||||
|
locators_ptrs.size()
|
||||||
|
);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
return result::err("Failed to join as core node: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string declaration_id = bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), sizeof(value));
|
std::string declaration_id = bytes_to_hex(reinterpret_cast<const uint8_t*>(&value), sizeof(value));
|
||||||
@ -1074,13 +1023,14 @@ StdLogosResult LogosBlockchainModule::get_block(const std::string& header_id_hex
|
|||||||
|
|
||||||
auto [value, error] = ::get_block(node, reinterpret_cast<const HeaderId*>(bytes.data()));
|
auto [value, error] = ::get_block(node, reinterpret_cast<const HeaderId*>(bytes.data()));
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to get block. Error: %d\n", error);
|
||||||
|
return result::err("Failed to get block: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string out(value);
|
std::string out(value);
|
||||||
OperationStatus free_status = free_cstring(value);
|
const OperationStatus free_status = free_cstring(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free block string: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free block string. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
return result::ok(std::move(out));
|
return result::ok(std::move(out));
|
||||||
}
|
}
|
||||||
@ -1092,13 +1042,14 @@ StdLogosResult LogosBlockchainModule::get_blocks(const uint64_t from_slot, const
|
|||||||
|
|
||||||
auto [value, error] = ::get_blocks(node, from_slot, to_slot);
|
auto [value, error] = ::get_blocks(node, from_slot, to_slot);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to get blocks. Error: %d\n", error);
|
||||||
|
return result::err("Failed to get blocks: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string out(value);
|
std::string out(value);
|
||||||
OperationStatus free_status = free_cstring(value);
|
const OperationStatus free_status = free_cstring(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free blocks string: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free blocks string. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
return result::ok(std::move(out));
|
return result::ok(std::move(out));
|
||||||
}
|
}
|
||||||
@ -1115,13 +1066,14 @@ StdLogosResult LogosBlockchainModule::get_transaction(const std::string& tx_hash
|
|||||||
|
|
||||||
auto [value, error] = ::get_transaction(node, reinterpret_cast<const TxHash*>(bytes.data()));
|
auto [value, error] = ::get_transaction(node, reinterpret_cast<const TxHash*>(bytes.data()));
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to get transaction. Error: %d\n", error);
|
||||||
|
return result::err("Failed to get transaction: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string out(value);
|
std::string out(value);
|
||||||
OperationStatus free_status = free_cstring(value);
|
const OperationStatus free_status = free_cstring(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free transaction string: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free transaction string. Error: %d\n", free_status);
|
||||||
}
|
}
|
||||||
return result::ok(std::move(out));
|
return result::ok(std::move(out));
|
||||||
}
|
}
|
||||||
@ -1135,80 +1087,20 @@ StdLogosResult LogosBlockchainModule::get_cryptarchia_info() const {
|
|||||||
|
|
||||||
auto [value, error] = ::get_cryptarchia_info(node);
|
auto [value, error] = ::get_cryptarchia_info(node);
|
||||||
if (!is_ok(&error)) {
|
if (!is_ok(&error)) {
|
||||||
return result::err(operation_status::take_message(error));
|
fprintf(stderr, "Failed to get cryptarchia info. Error: %d\n", error);
|
||||||
|
return result::err("Failed to get cryptarchia info: " + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
json obj;
|
json obj;
|
||||||
obj["lib"] = bytes_to_hex(reinterpret_cast<const uint8_t*>(value->lib), ADDRESS_BYTES);
|
obj["lib"] = bytes_to_hex(reinterpret_cast<const uint8_t*>(value->lib), ADDRESS_BYTES);
|
||||||
obj["lib_slot"] = static_cast<int64_t>(value->lib_slot);
|
|
||||||
obj["tip"] = bytes_to_hex(reinterpret_cast<const uint8_t*>(value->tip), ADDRESS_BYTES);
|
obj["tip"] = bytes_to_hex(reinterpret_cast<const uint8_t*>(value->tip), ADDRESS_BYTES);
|
||||||
obj["slot"] = static_cast<int64_t>(value->slot);
|
obj["slot"] = static_cast<int64_t>(value->slot);
|
||||||
obj["height"] = static_cast<int64_t>(value->height);
|
obj["height"] = static_cast<int64_t>(value->height);
|
||||||
switch (value->mode) {
|
obj["mode"] = (value->mode == State::Online) ? "Online" : "Bootstrapping";
|
||||||
case State::Online:
|
|
||||||
obj["mode"] = "Online";
|
|
||||||
break;
|
|
||||||
case State::NotStarted:
|
|
||||||
obj["mode"] = "NotStarted";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
obj["mode"] = "Bootstrapping";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationStatus free_status = free_cryptarchia_info(value);
|
const OperationStatus free_status = free_cryptarchia_info(value);
|
||||||
if (!is_ok(&free_status)) {
|
if (!is_ok(&free_status)) {
|
||||||
fprintf(stderr, "Failed to free cryptarchia info: %s\n", operation_status::take_message(free_status).c_str());
|
fprintf(stderr, "Failed to free cryptarchia info. Error: %d\n", free_status);
|
||||||
}
|
|
||||||
return result::ok(obj.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::get_block_events(const std::string& header_id_hex) const {
|
|
||||||
if (!node) {
|
|
||||||
return result::err("The node is not running.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<uint8_t> bytes = parse_address_hex(header_id_hex);
|
|
||||||
if (bytes.empty() || static_cast<int>(bytes.size()) != ADDRESS_BYTES) {
|
|
||||||
return result::err("Header ID must be 64 hex characters (32 bytes).");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto [value, error] = ::get_block_events(node, reinterpret_cast<const HeaderId*>(bytes.data()));
|
|
||||||
if (!is_ok(&error)) {
|
|
||||||
return result::err(operation_status::take_message(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string out(value);
|
|
||||||
OperationStatus free_status = free_cstring(value);
|
|
||||||
if (!is_ok(&free_status)) {
|
|
||||||
fprintf(
|
|
||||||
stderr, "Failed to free block events string: %s\n", operation_status::take_message(free_status).c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return result::ok(std::move(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time
|
|
||||||
|
|
||||||
StdLogosResult LogosBlockchainModule::get_time_info() const {
|
|
||||||
if (!node) {
|
|
||||||
return result::err("The node is not running.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto [value, error] = ::get_time_info(node);
|
|
||||||
if (!is_ok(&error)) {
|
|
||||||
return result::err(operation_status::take_message(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
json obj;
|
|
||||||
obj["slot_duration_ms"] = static_cast<int64_t>(value->slot_duration_ms);
|
|
||||||
obj["genesis_time_unix_ms"] = value->genesis_time_unix_ms;
|
|
||||||
obj["current_slot"] = static_cast<int64_t>(value->current_slot);
|
|
||||||
obj["current_epoch"] = value->current_epoch;
|
|
||||||
|
|
||||||
OperationStatus free_status = free_time_info(value);
|
|
||||||
if (!is_ok(&free_status)) {
|
|
||||||
fprintf(stderr, "Failed to free time info: %s\n", operation_status::take_message(free_status).c_str());
|
|
||||||
}
|
}
|
||||||
return result::ok(obj.dump());
|
return result::ok(obj.dump());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public:
|
|||||||
// state/storage/logs path always wins; output is always re-anchored under the
|
// state/storage/logs path always wins; output is always re-anchored under the
|
||||||
// base when flagged. On success the result value is the path the config was
|
// base when flagged. On success the result value is the path the config was
|
||||||
// written to — pass it straight to start().
|
// written to — pass it straight to start().
|
||||||
[[nodiscard]] StdLogosResult generate_user_config(const std::string& json_args) const;
|
[[nodiscard]] StdLogosResult generate_user_config(const std::string& json_args);
|
||||||
[[nodiscard]] static StdLogosResult update_user_config(
|
[[nodiscard]] static StdLogosResult update_user_config(
|
||||||
const std::string& user_config_path,
|
const std::string& user_config_path,
|
||||||
const std::string& keystore_path
|
const std::string& keystore_path
|
||||||
@ -99,16 +99,6 @@ public:
|
|||||||
) const;
|
) const;
|
||||||
[[nodiscard]] StdLogosResult leader_claim() const;
|
[[nodiscard]] StdLogosResult leader_claim() const;
|
||||||
[[nodiscard]] StdLogosResult wallet_get_claimable_vouchers() const;
|
[[nodiscard]] StdLogosResult wallet_get_claimable_vouchers() const;
|
||||||
// Funds an unsigned transaction: request_json is passed through to the
|
|
||||||
// node's wallet fund endpoint (same JSON schema as the HTTP `/wallet/fund`
|
|
||||||
// request body); returns the funded transaction as JSON.
|
|
||||||
[[nodiscard]] StdLogosResult wallet_fund_tx(const std::string& request_json) const;
|
|
||||||
|
|
||||||
// Transactions
|
|
||||||
// Submits a signed transaction: signed_tx_json is passed through to the
|
|
||||||
// node (same JSON schema as the HTTP `/mantle/transact` request body);
|
|
||||||
// returns the transaction hash hex on success.
|
|
||||||
[[nodiscard]] StdLogosResult submit_signed_transaction(const std::string& signed_tx_json) const;
|
|
||||||
|
|
||||||
// Channel
|
// Channel
|
||||||
// Amount-based deposit: the binding selects funding notes itself (splitting a
|
// Amount-based deposit: the binding selects funding notes itself (splitting a
|
||||||
@ -138,15 +128,12 @@ public:
|
|||||||
const std::string& optional_tip_hex
|
const std::string& optional_tip_hex
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
// State of the channel with the given 32-byte channel ID, as JSON (same
|
|
||||||
// schema as the node's `/mantle/channel/{id}` HTTP endpoint). Fails with a
|
|
||||||
// not-found error when the channel does not exist yet.
|
|
||||||
[[nodiscard]] StdLogosResult get_channel_state(const std::string& channel_id_hex) const;
|
|
||||||
|
|
||||||
// Blend
|
// Blend
|
||||||
[[nodiscard]] StdLogosResult blend_join_as_core_node(
|
[[nodiscard]] StdLogosResult blend_join_as_core_node(
|
||||||
const std::string& locator,
|
const std::string& provider_id_hex,
|
||||||
const std::string& locked_note_id_hex
|
const std::string& zk_id_hex,
|
||||||
|
const std::string& locked_note_id_hex,
|
||||||
|
const std::vector<std::string>& locators
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
// Explorer
|
// Explorer
|
||||||
@ -156,13 +143,6 @@ public:
|
|||||||
|
|
||||||
// Cryptarchia
|
// Cryptarchia
|
||||||
[[nodiscard]] StdLogosResult get_cryptarchia_info() const;
|
[[nodiscard]] StdLogosResult get_cryptarchia_info() const;
|
||||||
// Events emitted by the block with the given 32-byte header ID, as JSON.
|
|
||||||
[[nodiscard]] StdLogosResult get_block_events(const std::string& header_id_hex) const;
|
|
||||||
|
|
||||||
// Time
|
|
||||||
// Consensus time info as JSON:
|
|
||||||
// { slot_duration_ms, genesis_time_unix_ms, current_slot, current_epoch }
|
|
||||||
[[nodiscard]] StdLogosResult get_time_info() const;
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// Clang-format only handles public/private/protected, so it miss-indents this section.
|
// Clang-format only handles public/private/protected, so it miss-indents this section.
|
||||||
@ -172,19 +152,6 @@ logos_events:
|
|||||||
// blockJson is the full block serialized as JSON.
|
// blockJson is the full block serialized as JSON.
|
||||||
// ReSharper disable once CppFunctionIsNotImplemented
|
// ReSharper disable once CppFunctionIsNotImplemented
|
||||||
void newBlock(const std::string& blockJson);
|
void newBlock(const std::string& blockJson);
|
||||||
// Fired per processed block. eventJson carries the block plus the chain
|
|
||||||
// state after processing it (same schema as the node's
|
|
||||||
// `/cryptarchia/blocks/stream` HTTP endpoint; transaction ids at
|
|
||||||
// `transactions[].mantle_tx.hash`). When the stream ends, fired exactly
|
|
||||||
// once with the JSON literal `null` — restart the node subscription (via
|
|
||||||
// stop/start) to keep receiving events.
|
|
||||||
// ReSharper disable once CppFunctionIsNotImplemented
|
|
||||||
void processedBlock(const std::string& eventJson);
|
|
||||||
// Fired per newly finalized (LIB) block. blockInfoJson uses the same
|
|
||||||
// schema as the node's `/cryptarchia/lib/stream` HTTP endpoint. When the
|
|
||||||
// stream ends, fired exactly once with the JSON literal `null`.
|
|
||||||
// ReSharper disable once CppFunctionIsNotImplemented
|
|
||||||
void libBlock(const std::string& blockInfoJson);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -193,10 +160,6 @@ private:
|
|||||||
// Static instance for C callback (C API doesn't support user data)
|
// Static instance for C callback (C API doesn't support user data)
|
||||||
static LogosBlockchainModule* s_instance;
|
static LogosBlockchainModule* s_instance;
|
||||||
|
|
||||||
// C-compatible callback functions. The stream callbacks receive NULL
|
// C-compatible callback function
|
||||||
// exactly once when their stream ends; that is forwarded as the JSON
|
|
||||||
// literal `null` on the corresponding event.
|
|
||||||
static void on_new_block_callback(const char* block);
|
static void on_new_block_callback(const char* block);
|
||||||
static void on_processed_block_callback(const char* event);
|
|
||||||
static void on_lib_block_callback(const char* event);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,23 +12,6 @@
|
|||||||
|
|
||||||
#include "logos_blockchain_module.h"
|
#include "logos_blockchain_module.h"
|
||||||
|
|
||||||
// Recorded payloads of the most recent stream events, so tests can assert what
|
|
||||||
// the trampolines forwarded (including the `null` end-of-stream sentinel).
|
|
||||||
std::string g_lastNewBlockEventJson;
|
|
||||||
std::string g_lastProcessedBlockEventJson;
|
|
||||||
std::string g_lastLibBlockEventJson;
|
|
||||||
|
|
||||||
void LogosBlockchainModule::newBlock(const std::string& blockJson) {
|
void LogosBlockchainModule::newBlock(const std::string& blockJson) {
|
||||||
g_lastNewBlockEventJson = blockJson;
|
|
||||||
emitEventImpl_("newBlock", nullptr);
|
emitEventImpl_("newBlock", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogosBlockchainModule::processedBlock(const std::string& eventJson) {
|
|
||||||
g_lastProcessedBlockEventJson = eventJson;
|
|
||||||
emitEventImpl_("processedBlock", nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogosBlockchainModule::libBlock(const std::string& blockInfoJson) {
|
|
||||||
g_lastLibBlockEventJson = blockInfoJson;
|
|
||||||
emitEventImpl_("libBlock", nullptr);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -16,12 +16,6 @@ std::string g_lastGeneratedStatePath;
|
|||||||
std::string g_lastGeneratedStoragePath;
|
std::string g_lastGeneratedStoragePath;
|
||||||
std::string g_lastGeneratedLogsPath;
|
std::string g_lastGeneratedLogsPath;
|
||||||
|
|
||||||
// Captures the callbacks passed to the subscription calls so tests can drive
|
|
||||||
// the streams (including the NULL end-of-stream sentinel).
|
|
||||||
BlockCallback g_lastNewBlockCallback = nullptr;
|
|
||||||
BlockCallback g_lastProcessedBlockCallback = nullptr;
|
|
||||||
BlockCallback g_lastLibBlockCallback = nullptr;
|
|
||||||
|
|
||||||
static char s_fakeNode = 0;
|
static char s_fakeNode = 0;
|
||||||
static CryptarchiaInfo s_fakeCryptarchiaInfo = {};
|
static CryptarchiaInfo s_fakeCryptarchiaInfo = {};
|
||||||
|
|
||||||
@ -33,17 +27,10 @@ static uint8_t s_mockAddr3[32];
|
|||||||
static uint8_t* s_mockAddrs[] = { s_mockAddr0, s_mockAddr1, s_mockAddr2, s_mockAddr3 };
|
static uint8_t* s_mockAddrs[] = { s_mockAddr0, s_mockAddr1, s_mockAddr2, s_mockAddr3 };
|
||||||
static ClaimableVoucher s_mockClaimableVouchers[4];
|
static ClaimableVoucher s_mockClaimableVouchers[4];
|
||||||
|
|
||||||
static OperationStatus make_status(int code) {
|
|
||||||
OperationStatus s;
|
|
||||||
s.code = static_cast<OperationStatusCode>(code);
|
|
||||||
s.message = code != 0 ? strdup("mock error") : nullptr;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
bool is_ok(const OperationStatus* status) {
|
bool is_ok(const OperationStatus* status) {
|
||||||
return status && status->code == OperationStatusCode_Ok;
|
return status && *status == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus generate_user_config(GenerateConfigArgs args) {
|
OperationStatus generate_user_config(GenerateConfigArgs args) {
|
||||||
@ -52,7 +39,7 @@ OperationStatus generate_user_config(GenerateConfigArgs args) {
|
|||||||
g_lastGeneratedStatePath = args.state_path ? args.state_path : "<null>";
|
g_lastGeneratedStatePath = args.state_path ? args.state_path : "<null>";
|
||||||
g_lastGeneratedStoragePath = args.storage_path ? args.storage_path : "<null>";
|
g_lastGeneratedStoragePath = args.storage_path ? args.storage_path : "<null>";
|
||||||
g_lastGeneratedLogsPath = args.logs_path ? args.logs_path : "<null>";
|
g_lastGeneratedLogsPath = args.logs_path ? args.logs_path : "<null>";
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "generate_user_config"));
|
return LOGOS_CMOCK_RETURN(int, "generate_user_config");
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeResult start_lb_node(const char* config_path, const char* deployment) {
|
NodeResult start_lb_node(const char* config_path, const char* deployment) {
|
||||||
@ -60,23 +47,23 @@ NodeResult start_lb_node(const char* config_path, const char* deployment) {
|
|||||||
int ok = LOGOS_CMOCK_RETURN(int, "start_lb_node");
|
int ok = LOGOS_CMOCK_RETURN(int, "start_lb_node");
|
||||||
NodeResult result;
|
NodeResult result;
|
||||||
result.value = ok ? reinterpret_cast<LogosBlockchainNode*>(&s_fakeNode) : nullptr;
|
result.value = ok ? reinterpret_cast<LogosBlockchainNode*>(&s_fakeNode) : nullptr;
|
||||||
result.error = make_status(ok ? 0 : 1);
|
result.error = ok ? 0 : 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus shutdown_node(LogosBlockchainNode* node) {
|
OperationStatus stop_node(LogosBlockchainNode* node) {
|
||||||
LOGOS_CMOCK_RECORD("shutdown_node");
|
LOGOS_CMOCK_RECORD("stop_node");
|
||||||
return make_status(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus update_user_config(const char* user_config_path, const char* keystore_path) {
|
OperationStatus update_user_config(const char* user_config_path, const char* keystore_path) {
|
||||||
LOGOS_CMOCK_RECORD("update_user_config");
|
LOGOS_CMOCK_RECORD("update_user_config");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "update_user_config"));
|
return LOGOS_CMOCK_RETURN(int, "update_user_config");
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus migrate_user_config(const char* output_path, const char* keystore_path) {
|
OperationStatus migrate_user_config(const char* output_path, const char* keystore_path) {
|
||||||
LOGOS_CMOCK_RECORD("migrate_user_config");
|
LOGOS_CMOCK_RECORD("migrate_user_config");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "migrate_user_config"));
|
return LOGOS_CMOCK_RETURN(int, "migrate_user_config");
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus migrate_user_config_0_1_2(
|
OperationStatus migrate_user_config_0_1_2(
|
||||||
@ -85,7 +72,7 @@ OperationStatus migrate_user_config_0_1_2(
|
|||||||
const char* keystore_path)
|
const char* keystore_path)
|
||||||
{
|
{
|
||||||
LOGOS_CMOCK_RECORD("migrate_user_config_0_1_2");
|
LOGOS_CMOCK_RECORD("migrate_user_config_0_1_2");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "migrate_user_config_0_1_2"));
|
return LOGOS_CMOCK_RETURN(int, "migrate_user_config_0_1_2");
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus participate(
|
OperationStatus participate(
|
||||||
@ -95,7 +82,7 @@ OperationStatus participate(
|
|||||||
const char* external_address)
|
const char* external_address)
|
||||||
{
|
{
|
||||||
LOGOS_CMOCK_RECORD("participate");
|
LOGOS_CMOCK_RECORD("participate");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "participate"));
|
return LOGOS_CMOCK_RETURN(int, "participate");
|
||||||
}
|
}
|
||||||
|
|
||||||
StringResult generate_key(
|
StringResult generate_key(
|
||||||
@ -108,7 +95,7 @@ StringResult generate_key(
|
|||||||
StringResult result;
|
StringResult result;
|
||||||
const char* id = LOGOS_CMOCK_RETURN_STRING("generate_key");
|
const char* id = LOGOS_CMOCK_RETURN_STRING("generate_key");
|
||||||
result.value = id ? strdup(id) : nullptr;
|
result.value = id ? strdup(id) : nullptr;
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "generate_key_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "generate_key_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +107,7 @@ OperationStatus add_key(
|
|||||||
const char* key_title)
|
const char* key_title)
|
||||||
{
|
{
|
||||||
LOGOS_CMOCK_RECORD("add_key");
|
LOGOS_CMOCK_RECORD("add_key");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "add_key"));
|
return LOGOS_CMOCK_RETURN(int, "add_key");
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus remove_key(
|
OperationStatus remove_key(
|
||||||
@ -129,7 +116,7 @@ OperationStatus remove_key(
|
|||||||
const char* key_title)
|
const char* key_title)
|
||||||
{
|
{
|
||||||
LOGOS_CMOCK_RECORD("remove_key");
|
LOGOS_CMOCK_RECORD("remove_key");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "remove_key"));
|
return LOGOS_CMOCK_RETURN(int, "remove_key");
|
||||||
}
|
}
|
||||||
|
|
||||||
StringResult get_peer_id(const char* config_path) {
|
StringResult get_peer_id(const char* config_path) {
|
||||||
@ -137,33 +124,20 @@ StringResult get_peer_id(const char* config_path) {
|
|||||||
StringResult result;
|
StringResult result;
|
||||||
const char* id = LOGOS_CMOCK_RETURN_STRING("get_peer_id");
|
const char* id = LOGOS_CMOCK_RETURN_STRING("get_peer_id");
|
||||||
result.value = id ? strdup(id) : nullptr;
|
result.value = id ? strdup(id) : nullptr;
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_peer_id_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "get_peer_id_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus subscribe_to_new_blocks(LogosBlockchainNode* node, BlockCallback callback) {
|
OperationStatus subscribe_to_new_blocks(LogosBlockchainNode* node, BlockCallback callback) {
|
||||||
LOGOS_CMOCK_RECORD("subscribe_to_new_blocks");
|
LOGOS_CMOCK_RECORD("subscribe_to_new_blocks");
|
||||||
g_lastNewBlockCallback = callback;
|
return LOGOS_CMOCK_RETURN(int, "subscribe_to_new_blocks");
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "subscribe_to_new_blocks"));
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationStatus subscribe_to_processed_blocks(LogosBlockchainNode* node, BlockCallback callback) {
|
|
||||||
LOGOS_CMOCK_RECORD("subscribe_to_processed_blocks");
|
|
||||||
g_lastProcessedBlockCallback = callback;
|
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "subscribe_to_processed_blocks"));
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationStatus subscribe_to_lib_blocks(LogosBlockchainNode* node, BlockCallback callback) {
|
|
||||||
LOGOS_CMOCK_RECORD("subscribe_to_lib_blocks");
|
|
||||||
g_lastLibBlockCallback = callback;
|
|
||||||
return make_status(LOGOS_CMOCK_RETURN(int, "subscribe_to_lib_blocks"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BalanceResult get_balance(LogosBlockchainNode* node, const uint8_t* address, const void* reserved) {
|
BalanceResult get_balance(LogosBlockchainNode* node, const uint8_t* address, const void* reserved) {
|
||||||
LOGOS_CMOCK_RECORD("get_balance");
|
LOGOS_CMOCK_RECORD("get_balance");
|
||||||
BalanceResult result;
|
BalanceResult result;
|
||||||
result.value = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "get_balance_value"));
|
result.value = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "get_balance_value"));
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_balance_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "get_balance_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +145,7 @@ TransferHashResult transfer_funds(LogosBlockchainNode* node, const TransferFunds
|
|||||||
LOGOS_CMOCK_RECORD("transfer_funds");
|
LOGOS_CMOCK_RECORD("transfer_funds");
|
||||||
TransferHashResult result;
|
TransferHashResult result;
|
||||||
memset(result.value, 0xAB, sizeof(Hash));
|
memset(result.value, 0xAB, sizeof(Hash));
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "transfer_funds_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "transfer_funds_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +153,7 @@ FfiLeaderClaimResult leader_claim(LogosBlockchainNode* node) {
|
|||||||
LOGOS_CMOCK_RECORD("leader_claim");
|
LOGOS_CMOCK_RECORD("leader_claim");
|
||||||
FfiLeaderClaimResult result;
|
FfiLeaderClaimResult result;
|
||||||
memset(result.value, 0xEF, sizeof(TxHash));
|
memset(result.value, 0xEF, sizeof(TxHash));
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "leader_claim_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "leader_claim_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +161,7 @@ KnownAddressesResult get_known_addresses(LogosBlockchainNode* node) {
|
|||||||
LOGOS_CMOCK_RECORD("get_known_addresses");
|
LOGOS_CMOCK_RECORD("get_known_addresses");
|
||||||
KnownAddressesResult result;
|
KnownAddressesResult result;
|
||||||
int err = LOGOS_CMOCK_RETURN(int, "get_known_addresses_error");
|
int err = LOGOS_CMOCK_RETURN(int, "get_known_addresses_error");
|
||||||
result.error = make_status(err);
|
result.error = err;
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
int count = LOGOS_CMOCK_RETURN(int, "get_known_addresses_count");
|
int count = LOGOS_CMOCK_RETURN(int, "get_known_addresses_count");
|
||||||
if (count > 4) count = 4;
|
if (count > 4) count = 4;
|
||||||
@ -206,14 +180,14 @@ KnownAddressesResult get_known_addresses(LogosBlockchainNode* node) {
|
|||||||
|
|
||||||
OperationStatus free_known_addresses(KnownAddresses addrs) {
|
OperationStatus free_known_addresses(KnownAddresses addrs) {
|
||||||
LOGOS_CMOCK_RECORD("free_known_addresses");
|
LOGOS_CMOCK_RECORD("free_known_addresses");
|
||||||
return make_status(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, const HeaderId* optional_tip) {
|
FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, const HeaderId* optional_tip) {
|
||||||
LOGOS_CMOCK_RECORD("get_claimable_vouchers");
|
LOGOS_CMOCK_RECORD("get_claimable_vouchers");
|
||||||
FfiClaimableVouchersResult result;
|
FfiClaimableVouchersResult result;
|
||||||
int err = LOGOS_CMOCK_RETURN(int, "get_claimable_vouchers_error");
|
int err = LOGOS_CMOCK_RETURN(int, "get_claimable_vouchers_error");
|
||||||
result.error = make_status(err);
|
result.error = err;
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
int count = LOGOS_CMOCK_RETURN(int, "get_claimable_vouchers_count");
|
int count = LOGOS_CMOCK_RETURN(int, "get_claimable_vouchers_count");
|
||||||
if (count > 4) count = 4;
|
if (count > 4) count = 4;
|
||||||
@ -234,16 +208,7 @@ FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, con
|
|||||||
|
|
||||||
OperationStatus free_claimable_vouchers(ClaimableVouchers vouchers) {
|
OperationStatus free_claimable_vouchers(ClaimableVouchers vouchers) {
|
||||||
LOGOS_CMOCK_RECORD("free_claimable_vouchers");
|
LOGOS_CMOCK_RECORD("free_claimable_vouchers");
|
||||||
return make_status(0);
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
StringResult get_channel_state(LogosBlockchainNode* node, const uint8_t* channel_id) {
|
|
||||||
LOGOS_CMOCK_RECORD("get_channel_state");
|
|
||||||
StringResult result;
|
|
||||||
const char* json = LOGOS_CMOCK_RETURN_STRING("get_channel_state");
|
|
||||||
result.value = json ? strdup(json) : nullptr;
|
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_channel_state_error"));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wallet-notes mock storage (up to 4 notes)
|
// Wallet-notes mock storage (up to 4 notes)
|
||||||
@ -258,7 +223,7 @@ FfiWalletNotesResult get_wallet_notes(
|
|||||||
FfiWalletNotesResult result;
|
FfiWalletNotesResult result;
|
||||||
memset(&result.value, 0, sizeof(WalletNotes));
|
memset(&result.value, 0, sizeof(WalletNotes));
|
||||||
int err = LOGOS_CMOCK_RETURN(int, "get_wallet_notes_error");
|
int err = LOGOS_CMOCK_RETURN(int, "get_wallet_notes_error");
|
||||||
result.error = make_status(err);
|
result.error = err;
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
int count = LOGOS_CMOCK_RETURN(int, "get_wallet_notes_count");
|
int count = LOGOS_CMOCK_RETURN(int, "get_wallet_notes_count");
|
||||||
if (count > 4) count = 4;
|
if (count > 4) count = 4;
|
||||||
@ -276,31 +241,14 @@ FfiWalletNotesResult get_wallet_notes(
|
|||||||
|
|
||||||
OperationStatus free_wallet_notes(WalletNotes notes) {
|
OperationStatus free_wallet_notes(WalletNotes notes) {
|
||||||
LOGOS_CMOCK_RECORD("free_wallet_notes");
|
LOGOS_CMOCK_RECORD("free_wallet_notes");
|
||||||
return make_status(0);
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
StringResult wallet_fund_tx(LogosBlockchainNode* node, const char* request_json) {
|
|
||||||
LOGOS_CMOCK_RECORD("wallet_fund_tx");
|
|
||||||
StringResult result;
|
|
||||||
const char* json = LOGOS_CMOCK_RETURN_STRING("wallet_fund_tx");
|
|
||||||
result.value = json ? strdup(json) : nullptr;
|
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "wallet_fund_tx_error"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubmitTransactionResult submit_signed_transaction(LogosBlockchainNode* node, const char* signed_tx_json) {
|
|
||||||
LOGOS_CMOCK_RECORD("submit_signed_transaction");
|
|
||||||
SubmitTransactionResult result;
|
|
||||||
memset(result.value, 0xFA, sizeof(Hash));
|
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "submit_signed_transaction_error"));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FfiChannelDepositResult channel_deposit(LogosBlockchainNode* node, const ChannelDepositArguments* arguments) {
|
FfiChannelDepositResult channel_deposit(LogosBlockchainNode* node, const ChannelDepositArguments* arguments) {
|
||||||
LOGOS_CMOCK_RECORD("channel_deposit");
|
LOGOS_CMOCK_RECORD("channel_deposit");
|
||||||
FfiChannelDepositResult result;
|
FfiChannelDepositResult result;
|
||||||
memset(result.value, 0xBC, sizeof(Hash));
|
memset(result.value, 0xBC, sizeof(Hash));
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "channel_deposit_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "channel_deposit_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,19 +259,22 @@ FfiChannelDepositResult channel_deposit_with_notes(
|
|||||||
LOGOS_CMOCK_RECORD("channel_deposit_with_notes");
|
LOGOS_CMOCK_RECORD("channel_deposit_with_notes");
|
||||||
FfiChannelDepositResult result;
|
FfiChannelDepositResult result;
|
||||||
memset(result.value, 0xDE, sizeof(Hash));
|
memset(result.value, 0xDE, sizeof(Hash));
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "channel_deposit_with_notes_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "channel_deposit_with_notes_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlendHashResult blend_join_as_core_node(
|
BlendHashResult blend_join_as_core_node(
|
||||||
LogosBlockchainNode* node,
|
LogosBlockchainNode* node,
|
||||||
const char* locator,
|
const uint8_t* provider_id,
|
||||||
const uint8_t* locked_note_id)
|
const uint8_t* zk_id,
|
||||||
|
const uint8_t* locked_note_id,
|
||||||
|
const char** locators,
|
||||||
|
size_t locators_count)
|
||||||
{
|
{
|
||||||
LOGOS_CMOCK_RECORD("blend_join_as_core_node");
|
LOGOS_CMOCK_RECORD("blend_join_as_core_node");
|
||||||
BlendHashResult result;
|
BlendHashResult result;
|
||||||
memset(result.value, 0xCD, sizeof(Hash));
|
memset(result.value, 0xCD, sizeof(Hash));
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "blend_join_as_core_node_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "blend_join_as_core_node_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +283,7 @@ StringResult get_block(LogosBlockchainNode* node, const HeaderId* header_id) {
|
|||||||
StringResult result;
|
StringResult result;
|
||||||
const char* json = LOGOS_CMOCK_RETURN_STRING("get_block");
|
const char* json = LOGOS_CMOCK_RETURN_STRING("get_block");
|
||||||
result.value = json ? strdup(json) : nullptr;
|
result.value = json ? strdup(json) : nullptr;
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_block_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "get_block_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +292,7 @@ StringResult get_blocks(LogosBlockchainNode* node, uint64_t from_slot, uint64_t
|
|||||||
StringResult result;
|
StringResult result;
|
||||||
const char* json = LOGOS_CMOCK_RETURN_STRING("get_blocks");
|
const char* json = LOGOS_CMOCK_RETURN_STRING("get_blocks");
|
||||||
result.value = json ? strdup(json) : nullptr;
|
result.value = json ? strdup(json) : nullptr;
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_blocks_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "get_blocks_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +301,7 @@ StringResult get_transaction(LogosBlockchainNode* node, const TxHash* tx_hash) {
|
|||||||
StringResult result;
|
StringResult result;
|
||||||
const char* json = LOGOS_CMOCK_RETURN_STRING("get_transaction");
|
const char* json = LOGOS_CMOCK_RETURN_STRING("get_transaction");
|
||||||
result.value = json ? strdup(json) : nullptr;
|
result.value = json ? strdup(json) : nullptr;
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_transaction_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "get_transaction_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,54 +309,25 @@ CryptarchiaInfoResult get_cryptarchia_info(LogosBlockchainNode* node) {
|
|||||||
LOGOS_CMOCK_RECORD("get_cryptarchia_info");
|
LOGOS_CMOCK_RECORD("get_cryptarchia_info");
|
||||||
CryptarchiaInfoResult result;
|
CryptarchiaInfoResult result;
|
||||||
memset(&s_fakeCryptarchiaInfo, 0, sizeof(s_fakeCryptarchiaInfo));
|
memset(&s_fakeCryptarchiaInfo, 0, sizeof(s_fakeCryptarchiaInfo));
|
||||||
s_fakeCryptarchiaInfo.lib_slot = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "cryptarchia_lib_slot"));
|
|
||||||
s_fakeCryptarchiaInfo.slot = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "cryptarchia_slot"));
|
s_fakeCryptarchiaInfo.slot = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "cryptarchia_slot"));
|
||||||
s_fakeCryptarchiaInfo.height = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "cryptarchia_height"));
|
s_fakeCryptarchiaInfo.height = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "cryptarchia_height"));
|
||||||
s_fakeCryptarchiaInfo.mode = static_cast<State>(LOGOS_CMOCK_RETURN(int, "cryptarchia_mode"));
|
s_fakeCryptarchiaInfo.mode = static_cast<State>(LOGOS_CMOCK_RETURN(int, "cryptarchia_mode"));
|
||||||
memset(s_fakeCryptarchiaInfo.lib, 0xEE, 32);
|
memset(s_fakeCryptarchiaInfo.lib, 0xEE, 32);
|
||||||
memset(s_fakeCryptarchiaInfo.tip, 0xFF, 32);
|
memset(s_fakeCryptarchiaInfo.tip, 0xFF, 32);
|
||||||
result.value = &s_fakeCryptarchiaInfo;
|
result.value = &s_fakeCryptarchiaInfo;
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_cryptarchia_info_error"));
|
result.error = LOGOS_CMOCK_RETURN(int, "get_cryptarchia_info_error");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus free_cryptarchia_info(CryptarchiaInfo* info) {
|
OperationStatus free_cryptarchia_info(CryptarchiaInfo* info) {
|
||||||
LOGOS_CMOCK_RECORD("free_cryptarchia_info");
|
LOGOS_CMOCK_RECORD("free_cryptarchia_info");
|
||||||
return make_status(0);
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
StringResult get_block_events(LogosBlockchainNode* node, const HeaderId* header_id) {
|
|
||||||
LOGOS_CMOCK_RECORD("get_block_events");
|
|
||||||
StringResult result;
|
|
||||||
const char* json = LOGOS_CMOCK_RETURN_STRING("get_block_events");
|
|
||||||
result.value = json ? strdup(json) : nullptr;
|
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_block_events_error"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TimeInfo s_fakeTimeInfo = {};
|
|
||||||
|
|
||||||
TimeInfoResult get_time_info(LogosBlockchainNode* node) {
|
|
||||||
LOGOS_CMOCK_RECORD("get_time_info");
|
|
||||||
TimeInfoResult result;
|
|
||||||
s_fakeTimeInfo.slot_duration_ms = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "time_slot_duration_ms"));
|
|
||||||
s_fakeTimeInfo.genesis_time_unix_ms = static_cast<int64_t>(LOGOS_CMOCK_RETURN(int, "time_genesis_time_unix_ms"));
|
|
||||||
s_fakeTimeInfo.current_slot = static_cast<uint64_t>(LOGOS_CMOCK_RETURN(int, "time_current_slot"));
|
|
||||||
s_fakeTimeInfo.current_epoch = static_cast<uint32_t>(LOGOS_CMOCK_RETURN(int, "time_current_epoch"));
|
|
||||||
result.value = &s_fakeTimeInfo;
|
|
||||||
result.error = make_status(LOGOS_CMOCK_RETURN(int, "get_time_info_error"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationStatus free_time_info(TimeInfo* info) {
|
|
||||||
LOGOS_CMOCK_RECORD("free_time_info");
|
|
||||||
return make_status(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationStatus free_cstring(char* s) {
|
OperationStatus free_cstring(char* s) {
|
||||||
LOGOS_CMOCK_RECORD("free_cstring");
|
LOGOS_CMOCK_RECORD("free_cstring");
|
||||||
free(s);
|
free(s);
|
||||||
return make_status(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@ -21,31 +21,11 @@ typedef Hash NoteId;
|
|||||||
// Opaque node handle
|
// Opaque node handle
|
||||||
typedef struct LogosBlockchainNode LogosBlockchainNode;
|
typedef struct LogosBlockchainNode LogosBlockchainNode;
|
||||||
|
|
||||||
// Operation status code (0 = OK)
|
// Operation status (0 = OK)
|
||||||
typedef enum OperationStatusCode {
|
typedef int OperationStatus;
|
||||||
OperationStatusCode_Ok = 0,
|
|
||||||
OperationStatusCode_NotFound = 1,
|
|
||||||
OperationStatusCode_NullPointer = 2,
|
|
||||||
OperationStatusCode_RelayError = 3,
|
|
||||||
OperationStatusCode_ChannelSendError = 4,
|
|
||||||
OperationStatusCode_ChannelReceiveError = 5,
|
|
||||||
OperationStatusCode_ServiceError = 6,
|
|
||||||
OperationStatusCode_RuntimeError = 7,
|
|
||||||
OperationStatusCode_DynError = 8,
|
|
||||||
OperationStatusCode_InitializationError = 9,
|
|
||||||
OperationStatusCode_StopError = 10,
|
|
||||||
OperationStatusCode_ConfigurationError = 11,
|
|
||||||
OperationStatusCode_ValidationError = 12,
|
|
||||||
} OperationStatusCode;
|
|
||||||
|
|
||||||
// Operation status: code + Rust-allocated error message (free with free_cstring).
|
|
||||||
typedef struct {
|
|
||||||
OperationStatusCode code;
|
|
||||||
char* message;
|
|
||||||
} OperationStatus;
|
|
||||||
|
|
||||||
// Consensus state enum
|
// Consensus state enum
|
||||||
typedef enum { Bootstrapping, Online, NotStarted } State;
|
typedef enum { Bootstrapping, Online } State;
|
||||||
|
|
||||||
// Key type for generate_key / add_key
|
// Key type for generate_key / add_key
|
||||||
typedef enum { Ed25519, Zk } KeyType;
|
typedef enum { Ed25519, Zk } KeyType;
|
||||||
@ -62,7 +42,7 @@ typedef struct {
|
|||||||
const char* state_path;
|
const char* state_path;
|
||||||
const char* storage_path;
|
const char* storage_path;
|
||||||
const char* logs_path;
|
const char* logs_path;
|
||||||
const bool* skip_ibd;
|
const bool* ibd;
|
||||||
const char* log_filter;
|
const char* log_filter;
|
||||||
const char* kms_file;
|
const char* kms_file;
|
||||||
} GenerateConfigArgs;
|
} GenerateConfigArgs;
|
||||||
@ -134,21 +114,12 @@ typedef struct {
|
|||||||
// Cryptarchia consensus info
|
// Cryptarchia consensus info
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t lib[32];
|
uint8_t lib[32];
|
||||||
uint64_t lib_slot;
|
|
||||||
uint8_t tip[32];
|
uint8_t tip[32];
|
||||||
uint64_t slot;
|
uint64_t slot;
|
||||||
uint64_t height;
|
uint64_t height;
|
||||||
State mode;
|
State mode;
|
||||||
} CryptarchiaInfo;
|
} CryptarchiaInfo;
|
||||||
|
|
||||||
// Time service info
|
|
||||||
typedef struct {
|
|
||||||
uint64_t slot_duration_ms;
|
|
||||||
int64_t genesis_time_unix_ms;
|
|
||||||
uint64_t current_slot;
|
|
||||||
uint32_t current_epoch;
|
|
||||||
} TimeInfo;
|
|
||||||
|
|
||||||
// Result types (C++ structured bindings decompose these)
|
// Result types (C++ structured bindings decompose these)
|
||||||
typedef struct { LogosBlockchainNode* value; OperationStatus error; } NodeResult;
|
typedef struct { LogosBlockchainNode* value; OperationStatus error; } NodeResult;
|
||||||
typedef struct { uint64_t value; OperationStatus error; } BalanceResult;
|
typedef struct { uint64_t value; OperationStatus error; } BalanceResult;
|
||||||
@ -161,8 +132,6 @@ typedef struct { ClaimableVouchers value; OperationStatus error; } FfiClaimableV
|
|||||||
typedef struct { Hash value; OperationStatus error; } BlendHashResult;
|
typedef struct { Hash value; OperationStatus error; } BlendHashResult;
|
||||||
typedef struct { char* value; OperationStatus error; } StringResult;
|
typedef struct { char* value; OperationStatus error; } StringResult;
|
||||||
typedef struct { CryptarchiaInfo* value; OperationStatus error; } CryptarchiaInfoResult;
|
typedef struct { CryptarchiaInfo* value; OperationStatus error; } CryptarchiaInfoResult;
|
||||||
typedef struct { TimeInfo* value; OperationStatus error; } TimeInfoResult;
|
|
||||||
typedef struct { Hash value; OperationStatus error; } SubmitTransactionResult;
|
|
||||||
|
|
||||||
// Block event callback
|
// Block event callback
|
||||||
typedef void (*BlockCallback)(const char* block_json);
|
typedef void (*BlockCallback)(const char* block_json);
|
||||||
@ -173,12 +142,8 @@ bool is_ok(const OperationStatus* status);
|
|||||||
// Lifecycle
|
// Lifecycle
|
||||||
OperationStatus generate_user_config(GenerateConfigArgs args);
|
OperationStatus generate_user_config(GenerateConfigArgs args);
|
||||||
NodeResult start_lb_node(const char* config_path, const char* deployment);
|
NodeResult start_lb_node(const char* config_path, const char* deployment);
|
||||||
OperationStatus shutdown_node(LogosBlockchainNode* node);
|
OperationStatus stop_node(LogosBlockchainNode* node);
|
||||||
OperationStatus subscribe_to_new_blocks(LogosBlockchainNode* node, BlockCallback callback);
|
OperationStatus subscribe_to_new_blocks(LogosBlockchainNode* node, BlockCallback callback);
|
||||||
// Streams: each event is a JSON C string; the callback is invoked exactly once
|
|
||||||
// with NULL when the stream ends.
|
|
||||||
OperationStatus subscribe_to_processed_blocks(LogosBlockchainNode* node, BlockCallback callback);
|
|
||||||
OperationStatus subscribe_to_lib_blocks(LogosBlockchainNode* node, BlockCallback callback);
|
|
||||||
|
|
||||||
// Config management
|
// Config management
|
||||||
OperationStatus update_user_config(const char* user_config_path, const char* keystore_path);
|
OperationStatus update_user_config(const char* user_config_path, const char* keystore_path);
|
||||||
@ -224,10 +189,6 @@ FfiWalletNotesResult get_wallet_notes(
|
|||||||
const uint8_t* wallet_address,
|
const uint8_t* wallet_address,
|
||||||
const HeaderId* optional_tip);
|
const HeaderId* optional_tip);
|
||||||
OperationStatus free_wallet_notes(WalletNotes notes);
|
OperationStatus free_wallet_notes(WalletNotes notes);
|
||||||
StringResult wallet_fund_tx(LogosBlockchainNode* node, const char* request_json);
|
|
||||||
|
|
||||||
// Transactions
|
|
||||||
SubmitTransactionResult submit_signed_transaction(LogosBlockchainNode* node, const char* signed_tx_json);
|
|
||||||
|
|
||||||
// Channel
|
// Channel
|
||||||
FfiChannelDepositResult channel_deposit(LogosBlockchainNode* node, const ChannelDepositArguments* arguments);
|
FfiChannelDepositResult channel_deposit(LogosBlockchainNode* node, const ChannelDepositArguments* arguments);
|
||||||
@ -236,13 +197,15 @@ FfiChannelDepositResult channel_deposit_with_notes(
|
|||||||
const ChannelDepositWithNotesArguments* arguments);
|
const ChannelDepositWithNotesArguments* arguments);
|
||||||
FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, const HeaderId* optional_tip);
|
FfiClaimableVouchersResult get_claimable_vouchers(LogosBlockchainNode* node, const HeaderId* optional_tip);
|
||||||
OperationStatus free_claimable_vouchers(ClaimableVouchers vouchers);
|
OperationStatus free_claimable_vouchers(ClaimableVouchers vouchers);
|
||||||
StringResult get_channel_state(LogosBlockchainNode* node, const uint8_t* channel_id);
|
|
||||||
|
|
||||||
// Blend
|
// Blend
|
||||||
BlendHashResult blend_join_as_core_node(
|
BlendHashResult blend_join_as_core_node(
|
||||||
LogosBlockchainNode* node,
|
LogosBlockchainNode* node,
|
||||||
const char* locator,
|
const uint8_t* provider_id,
|
||||||
const uint8_t* locked_note_id);
|
const uint8_t* zk_id,
|
||||||
|
const uint8_t* locked_note_id,
|
||||||
|
const char** locators,
|
||||||
|
size_t locators_count);
|
||||||
|
|
||||||
// Explorer
|
// Explorer
|
||||||
StringResult get_block(LogosBlockchainNode* node, const HeaderId* header_id);
|
StringResult get_block(LogosBlockchainNode* node, const HeaderId* header_id);
|
||||||
@ -252,11 +215,6 @@ StringResult get_transaction(LogosBlockchainNode* node, const TxHash* tx_hash);
|
|||||||
// Cryptarchia
|
// Cryptarchia
|
||||||
CryptarchiaInfoResult get_cryptarchia_info(LogosBlockchainNode* node);
|
CryptarchiaInfoResult get_cryptarchia_info(LogosBlockchainNode* node);
|
||||||
OperationStatus free_cryptarchia_info(CryptarchiaInfo* info);
|
OperationStatus free_cryptarchia_info(CryptarchiaInfo* info);
|
||||||
StringResult get_block_events(LogosBlockchainNode* node, const HeaderId* header_id);
|
|
||||||
|
|
||||||
// Time
|
|
||||||
TimeInfoResult get_time_info(LogosBlockchainNode* node);
|
|
||||||
OperationStatus free_time_info(TimeInfo* info);
|
|
||||||
|
|
||||||
// Memory management
|
// Memory management
|
||||||
OperationStatus free_cstring(char* s);
|
OperationStatus free_cstring(char* s);
|
||||||
|
|||||||
@ -292,7 +292,7 @@ LOGOS_TEST(wallet_get_known_addresses_without_node_returns_error) {
|
|||||||
LOGOS_TEST(blend_join_as_core_node_without_node_returns_error) {
|
LOGOS_TEST(blend_join_as_core_node_without_node_returns_error) {
|
||||||
auto t = LogosTestContext("blockchain_module");
|
auto t = LogosTestContext("blockchain_module");
|
||||||
LogosBlockchainModule module;
|
LogosBlockchainModule module;
|
||||||
StdLogosResult result = module.blend_join_as_core_node("locator1", VALID_HEX);
|
StdLogosResult result = module.blend_join_as_core_node(VALID_HEX, VALID_HEX, VALID_HEX, {"locator1"});
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "not running"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "not running"));
|
||||||
}
|
}
|
||||||
@ -321,42 +321,6 @@ LOGOS_TEST(get_cryptarchia_info_without_node_returns_error) {
|
|||||||
LOGOS_ASSERT_FALSE(module.get_cryptarchia_info().success);
|
LOGOS_ASSERT_FALSE(module.get_cryptarchia_info().success);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGOS_TEST(get_block_events_without_node_returns_error) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
LOGOS_ASSERT_FALSE(module.get_block_events(VALID_HEX).success);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_time_info_without_node_returns_error) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
LOGOS_ASSERT_FALSE(module.get_time_info().success);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_channel_state_without_node_returns_error) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
StdLogosResult result = module.get_channel_state(VALID_HEX);
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "not running"));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(wallet_fund_tx_without_node_returns_error) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
StdLogosResult result = module.wallet_fund_tx("{}");
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "not running"));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(submit_signed_transaction_without_node_returns_error) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
StdLogosResult result = module.submit_signed_transaction("{}");
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "not running"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Node lifecycle (start / stop)
|
// Node lifecycle (start / stop)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -370,36 +334,9 @@ LOGOS_TEST(start_succeeds_with_mocked_dependencies) {
|
|||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
LOGOS_ASSERT_TRUE(module != nullptr);
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("start_lb_node"));
|
LOGOS_ASSERT(t.cFunctionCalled("start_lb_node"));
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("subscribe_to_new_blocks"));
|
LOGOS_ASSERT(t.cFunctionCalled("subscribe_to_new_blocks"));
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("subscribe_to_processed_blocks"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("subscribe_to_lib_blocks"));
|
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGOS_TEST(start_fails_when_processed_blocks_subscription_fails) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
|
|
||||||
t.mockCFunction("start_lb_node").returns(1);
|
|
||||||
t.mockCFunction("subscribe_to_new_blocks").returns(0);
|
|
||||||
t.mockCFunction("subscribe_to_processed_blocks").returns(1);
|
|
||||||
|
|
||||||
LOGOS_ASSERT_FALSE(module.start(tmpDir.filePath("config.json"), "").success);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(start_fails_when_lib_blocks_subscription_fails) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
LogosBlockchainModule module;
|
|
||||||
|
|
||||||
t.mockCFunction("start_lb_node").returns(1);
|
|
||||||
t.mockCFunction("subscribe_to_new_blocks").returns(0);
|
|
||||||
t.mockCFunction("subscribe_to_processed_blocks").returns(0);
|
|
||||||
t.mockCFunction("subscribe_to_lib_blocks").returns(1);
|
|
||||||
|
|
||||||
LOGOS_ASSERT_FALSE(module.start(tmpDir.filePath("config.json"), "").success);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(start_returns_1_when_already_running) {
|
LOGOS_TEST(start_returns_1_when_already_running) {
|
||||||
auto t = LogosTestContext("blockchain_module");
|
auto t = LogosTestContext("blockchain_module");
|
||||||
TempDir tmpDir;
|
TempDir tmpDir;
|
||||||
@ -417,7 +354,7 @@ LOGOS_TEST(stop_succeeds_with_running_node) {
|
|||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
LOGOS_ASSERT_TRUE(module != nullptr);
|
||||||
|
|
||||||
LOGOS_ASSERT_TRUE(module->stop().success);
|
LOGOS_ASSERT_TRUE(module->stop().success);
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("shutdown_node"));
|
LOGOS_ASSERT(t.cFunctionCalled("stop_node"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,15 +475,27 @@ LOGOS_TEST(wallet_transfer_funds_rejects_invalid_optional_tip) {
|
|||||||
|
|
||||||
// blend_join_as_core_node validation
|
// blend_join_as_core_node validation
|
||||||
|
|
||||||
LOGOS_TEST(blend_join_rejects_empty_locator) {
|
LOGOS_TEST(blend_join_rejects_invalid_provider_id) {
|
||||||
auto t = LogosTestContext("blockchain_module");
|
auto t = LogosTestContext("blockchain_module");
|
||||||
TempDir tmpDir;
|
TempDir tmpDir;
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
auto* module = createStartedModule(t, tmpDir);
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
LOGOS_ASSERT_TRUE(module != nullptr);
|
||||||
|
|
||||||
StdLogosResult result = module->blend_join_as_core_node("", VALID_HEX);
|
StdLogosResult result = module->blend_join_as_core_node("short", VALID_HEX, VALID_HEX, {});
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "locator"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "provider_id"));
|
||||||
|
delete module;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGOS_TEST(blend_join_rejects_invalid_zk_id) {
|
||||||
|
auto t = LogosTestContext("blockchain_module");
|
||||||
|
TempDir tmpDir;
|
||||||
|
auto* module = createStartedModule(t, tmpDir);
|
||||||
|
LOGOS_ASSERT_TRUE(module != nullptr);
|
||||||
|
|
||||||
|
StdLogosResult result = module->blend_join_as_core_node(VALID_HEX, "short", VALID_HEX, {});
|
||||||
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
|
LOGOS_ASSERT_TRUE(contains(result.error, "zk_id"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +505,7 @@ LOGOS_TEST(blend_join_rejects_invalid_locked_note_id) {
|
|||||||
auto* module = createStartedModule(t, tmpDir);
|
auto* module = createStartedModule(t, tmpDir);
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
LOGOS_ASSERT_TRUE(module != nullptr);
|
||||||
|
|
||||||
StdLogosResult result = module->blend_join_as_core_node("locator1", "short");
|
StdLogosResult result = module->blend_join_as_core_node(VALID_HEX, VALID_HEX, "short", {});
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "locked_note_id"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "locked_note_id"));
|
||||||
delete module;
|
delete module;
|
||||||
@ -588,30 +537,6 @@ LOGOS_TEST(get_transaction_rejects_invalid_hex) {
|
|||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGOS_TEST(get_block_events_rejects_invalid_hex) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_block_events("tooshort");
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "64 hex"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_channel_state_rejects_invalid_hex) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_channel_state("bad");
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "channel_id"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 0x prefix handling
|
// 0x prefix handling
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -737,6 +662,7 @@ LOGOS_TEST(leader_claim_returns_error_on_ffi_failure) {
|
|||||||
|
|
||||||
StdLogosResult result = module->leader_claim();
|
StdLogosResult result = module->leader_claim();
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
|
LOGOS_ASSERT_TRUE(contains(result.error, "Failed to claim leader rewards"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -781,7 +707,7 @@ LOGOS_TEST(channel_deposit_returns_error_on_ffi_failure) {
|
|||||||
|
|
||||||
StdLogosResult result = module->channel_deposit(VALID_HEX, VALID_HEX, "100", "", "");
|
StdLogosResult result = module->channel_deposit(VALID_HEX, VALID_HEX, "100", "", "");
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "Failed to deposit into channel"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,7 +829,7 @@ LOGOS_TEST(wallet_get_notes_returns_error_on_ffi_failure) {
|
|||||||
|
|
||||||
StdLogosResult result = module->wallet_get_notes(VALID_HEX, "");
|
StdLogosResult result = module->wallet_get_notes(VALID_HEX, "");
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "Failed to get wallet notes"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,7 +874,7 @@ LOGOS_TEST(channel_deposit_with_notes_returns_error_on_ffi_failure) {
|
|||||||
StdLogosResult result = module->channel_deposit_with_notes(
|
StdLogosResult result = module->channel_deposit_with_notes(
|
||||||
VALID_HEX, {VALID_HEX}, "", VALID_HEX, {VALID_HEX}, "0", "");
|
VALID_HEX, {VALID_HEX}, "", VALID_HEX, {VALID_HEX}, "0", "");
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "Failed to deposit into channel"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,105 +1022,7 @@ LOGOS_TEST(wallet_get_claimable_vouchers_returns_error_on_ffi_failure) {
|
|||||||
|
|
||||||
StdLogosResult result = module->wallet_get_claimable_vouchers();
|
StdLogosResult result = module->wallet_get_claimable_vouchers();
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
LOGOS_ASSERT_TRUE(contains(result.error, "Failed to get claimable vouchers"));
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(wallet_fund_tx_returns_json_on_success) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("wallet_fund_tx").returns(R"({"mantle_tx":{"ops":[]}})");
|
|
||||||
t.mockCFunction("wallet_fund_tx_error").returns(0);
|
|
||||||
|
|
||||||
StdLogosResult result = module->wallet_fund_tx(R"({"tx":{},"funding_keys":[]})");
|
|
||||||
LOGOS_ASSERT_TRUE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.value.get<std::string>(), "mantle_tx"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("wallet_fund_tx"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("free_cstring"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(wallet_fund_tx_returns_error_on_ffi_failure) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("wallet_fund_tx_error").returns(1);
|
|
||||||
|
|
||||||
StdLogosResult result = module->wallet_fund_tx("{}");
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transactions
|
|
||||||
|
|
||||||
LOGOS_TEST(submit_signed_transaction_returns_tx_hash) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("submit_signed_transaction_error").returns(0);
|
|
||||||
|
|
||||||
StdLogosResult result = module->submit_signed_transaction("{}");
|
|
||||||
LOGOS_ASSERT_TRUE(result.success);
|
|
||||||
// Mock fills hash with 0xFA -> hex "fafa...fa" (64 chars)
|
|
||||||
std::string hash = result.value.get<std::string>();
|
|
||||||
LOGOS_ASSERT_EQ(static_cast<int>(hash.length()), 64);
|
|
||||||
LOGOS_ASSERT_TRUE(hash.substr(0, 2) == "fa");
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("submit_signed_transaction"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(submit_signed_transaction_returns_error_on_ffi_failure) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("submit_signed_transaction_error").returns(1);
|
|
||||||
|
|
||||||
StdLogosResult result = module->submit_signed_transaction("{}");
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channel state
|
|
||||||
|
|
||||||
LOGOS_TEST(get_channel_state_returns_json_on_success) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_channel_state").returns(R"({"tip":"abc","inscriptions":[]})");
|
|
||||||
t.mockCFunction("get_channel_state_error").returns(0);
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_channel_state(VALID_HEX);
|
|
||||||
LOGOS_ASSERT_TRUE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.value.get<std::string>(), "inscriptions"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("get_channel_state"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("free_cstring"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_channel_state_returns_error_on_ffi_failure) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_channel_state_error").returns(1);
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_channel_state(VALID_HEX);
|
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.error, "mock error"));
|
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,7 +1036,8 @@ LOGOS_TEST(blend_join_as_core_node_returns_declaration_id) {
|
|||||||
|
|
||||||
t.mockCFunction("blend_join_as_core_node_error").returns(0);
|
t.mockCFunction("blend_join_as_core_node_error").returns(0);
|
||||||
|
|
||||||
StdLogosResult result = module->blend_join_as_core_node("locator1", VALID_HEX);
|
std::vector<std::string> locators = {"locator1", "locator2"};
|
||||||
|
StdLogosResult result = module->blend_join_as_core_node(VALID_HEX, VALID_HEX, VALID_HEX, locators);
|
||||||
LOGOS_ASSERT_TRUE(result.success);
|
LOGOS_ASSERT_TRUE(result.success);
|
||||||
// Mock fills hash with 0xCD -> hex "cdcd...cd" (64 chars)
|
// Mock fills hash with 0xCD -> hex "cdcd...cd" (64 chars)
|
||||||
std::string declarationId = result.value.get<std::string>();
|
std::string declarationId = result.value.get<std::string>();
|
||||||
@ -1226,7 +1055,7 @@ LOGOS_TEST(blend_join_as_core_node_returns_error_on_ffi_failure) {
|
|||||||
|
|
||||||
t.mockCFunction("blend_join_as_core_node_error").returns(1);
|
t.mockCFunction("blend_join_as_core_node_error").returns(1);
|
||||||
|
|
||||||
StdLogosResult result = module->blend_join_as_core_node("locator1", VALID_HEX);
|
StdLogosResult result = module->blend_join_as_core_node(VALID_HEX, VALID_HEX, VALID_HEX, {});
|
||||||
LOGOS_ASSERT_FALSE(result.success);
|
LOGOS_ASSERT_FALSE(result.success);
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
@ -1331,7 +1160,6 @@ LOGOS_TEST(get_cryptarchia_info_returns_json_on_success) {
|
|||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
LOGOS_ASSERT_TRUE(module != nullptr);
|
||||||
|
|
||||||
t.mockCFunction("get_cryptarchia_info_error").returns(0);
|
t.mockCFunction("get_cryptarchia_info_error").returns(0);
|
||||||
t.mockCFunction("cryptarchia_lib_slot").returns(90);
|
|
||||||
t.mockCFunction("cryptarchia_slot").returns(100);
|
t.mockCFunction("cryptarchia_slot").returns(100);
|
||||||
t.mockCFunction("cryptarchia_height").returns(50);
|
t.mockCFunction("cryptarchia_height").returns(50);
|
||||||
t.mockCFunction("cryptarchia_mode").returns(1); // Online
|
t.mockCFunction("cryptarchia_mode").returns(1); // Online
|
||||||
@ -1346,26 +1174,11 @@ LOGOS_TEST(get_cryptarchia_info_returns_json_on_success) {
|
|||||||
LOGOS_ASSERT_TRUE(contains(json, "Online"));
|
LOGOS_ASSERT_TRUE(contains(json, "Online"));
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "lib"));
|
LOGOS_ASSERT_TRUE(contains(json, "lib"));
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "tip"));
|
LOGOS_ASSERT_TRUE(contains(json, "tip"));
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "\"lib_slot\":90"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("get_cryptarchia_info"));
|
LOGOS_ASSERT(t.cFunctionCalled("get_cryptarchia_info"));
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("free_cryptarchia_info"));
|
LOGOS_ASSERT(t.cFunctionCalled("free_cryptarchia_info"));
|
||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGOS_TEST(get_cryptarchia_info_not_started_mode) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_cryptarchia_info_error").returns(0);
|
|
||||||
t.mockCFunction("cryptarchia_mode").returns(2); // NotStarted
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_cryptarchia_info();
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.value.get<std::string>(), "NotStarted"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_cryptarchia_info_bootstrapping_mode) {
|
LOGOS_TEST(get_cryptarchia_info_bootstrapping_mode) {
|
||||||
auto t = LogosTestContext("blockchain_module");
|
auto t = LogosTestContext("blockchain_module");
|
||||||
TempDir tmpDir;
|
TempDir tmpDir;
|
||||||
@ -1392,147 +1205,6 @@ LOGOS_TEST(get_cryptarchia_info_returns_error_on_ffi_failure) {
|
|||||||
delete module;
|
delete module;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGOS_TEST(get_block_events_returns_json_on_success) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_block_events").returns(R"([{"type":"inscription"}])");
|
|
||||||
t.mockCFunction("get_block_events_error").returns(0);
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_block_events(VALID_HEX);
|
|
||||||
LOGOS_ASSERT_TRUE(result.success);
|
|
||||||
LOGOS_ASSERT_TRUE(contains(result.value.get<std::string>(), "inscription"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("get_block_events"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("free_cstring"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_block_events_returns_error_on_ffi_failure) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_block_events_error").returns(1);
|
|
||||||
|
|
||||||
LOGOS_ASSERT_FALSE(module->get_block_events(VALID_HEX).success);
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time
|
|
||||||
|
|
||||||
LOGOS_TEST(get_time_info_returns_json_on_success) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_time_info_error").returns(0);
|
|
||||||
t.mockCFunction("time_slot_duration_ms").returns(2000);
|
|
||||||
t.mockCFunction("time_genesis_time_unix_ms").returns(1700000);
|
|
||||||
t.mockCFunction("time_current_slot").returns(1234);
|
|
||||||
t.mockCFunction("time_current_epoch").returns(7);
|
|
||||||
|
|
||||||
StdLogosResult result = module->get_time_info();
|
|
||||||
LOGOS_ASSERT_TRUE(result.success);
|
|
||||||
std::string json = result.value.get<std::string>();
|
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "\"slot_duration_ms\":2000"));
|
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "\"genesis_time_unix_ms\":1700000"));
|
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "\"current_slot\":1234"));
|
|
||||||
LOGOS_ASSERT_TRUE(contains(json, "\"current_epoch\":7"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("get_time_info"));
|
|
||||||
LOGOS_ASSERT(t.cFunctionCalled("free_time_info"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(get_time_info_returns_error_on_ffi_failure) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
|
|
||||||
t.mockCFunction("get_time_info_error").returns(1);
|
|
||||||
|
|
||||||
LOGOS_ASSERT_FALSE(module->get_time_info().success);
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Stream events (trampolines drive logos_events; end of stream = JSON null)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Captured by the mock subscribe calls (mock_logos_blockchain.cpp).
|
|
||||||
extern BlockCallback g_lastNewBlockCallback;
|
|
||||||
extern BlockCallback g_lastProcessedBlockCallback;
|
|
||||||
extern BlockCallback g_lastLibBlockCallback;
|
|
||||||
// Recorded by the event stubs (event_stubs.cpp).
|
|
||||||
extern std::string g_lastNewBlockEventJson;
|
|
||||||
extern std::string g_lastProcessedBlockEventJson;
|
|
||||||
extern std::string g_lastLibBlockEventJson;
|
|
||||||
|
|
||||||
LOGOS_TEST(processed_block_stream_forwards_json_and_null_sentinel) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
LOGOS_ASSERT_TRUE(g_lastProcessedBlockCallback != nullptr);
|
|
||||||
|
|
||||||
g_lastProcessedBlockEventJson.clear();
|
|
||||||
g_lastProcessedBlockCallback(R"({"header_id":"abc","transactions":[]})");
|
|
||||||
LOGOS_ASSERT_EQ(g_lastProcessedBlockEventJson, std::string(R"({"header_id":"abc","transactions":[]})"));
|
|
||||||
|
|
||||||
g_lastProcessedBlockCallback(nullptr);
|
|
||||||
LOGOS_ASSERT_EQ(g_lastProcessedBlockEventJson, std::string("null"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGOS_TEST(lib_block_stream_forwards_json_and_null_sentinel) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
LOGOS_ASSERT_TRUE(g_lastLibBlockCallback != nullptr);
|
|
||||||
|
|
||||||
g_lastLibBlockEventJson.clear();
|
|
||||||
g_lastLibBlockCallback(R"({"header_id":"def","slot":9})");
|
|
||||||
LOGOS_ASSERT_EQ(g_lastLibBlockEventJson, std::string(R"({"header_id":"def","slot":9})"));
|
|
||||||
|
|
||||||
g_lastLibBlockCallback(nullptr);
|
|
||||||
LOGOS_ASSERT_EQ(g_lastLibBlockEventJson, std::string("null"));
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The legacy new-block stream never sends NULL, but the trampoline must not
|
|
||||||
// crash if it ever does (regression test for the added guard).
|
|
||||||
LOGOS_TEST(new_block_callback_ignores_null_pointer) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
LOGOS_ASSERT_TRUE(g_lastNewBlockCallback != nullptr);
|
|
||||||
|
|
||||||
g_lastNewBlockEventJson.clear();
|
|
||||||
g_lastNewBlockCallback(nullptr);
|
|
||||||
LOGOS_ASSERT_EQ(g_lastNewBlockEventJson, std::string());
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stream events are not delivered after the module stops (s_instance cleared).
|
|
||||||
LOGOS_TEST(stream_events_not_delivered_after_stop) {
|
|
||||||
auto t = LogosTestContext("blockchain_module");
|
|
||||||
TempDir tmpDir;
|
|
||||||
auto* module = createStartedModule(t, tmpDir);
|
|
||||||
LOGOS_ASSERT_TRUE(module != nullptr);
|
|
||||||
LOGOS_ASSERT_TRUE(module->stop().success);
|
|
||||||
|
|
||||||
g_lastProcessedBlockEventJson.clear();
|
|
||||||
g_lastProcessedBlockCallback(R"({"header_id":"abc"})");
|
|
||||||
LOGOS_ASSERT_EQ(g_lastProcessedBlockEventJson, std::string());
|
|
||||||
delete module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Config management (operate on file paths, no running node required)
|
// Config management (operate on file paths, no running node required)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user