mirror of
https://github.com/logos-blockchain/logos-blockchain.git
synced 2026-01-02 05:03:10 +00:00
feat(c-bindings): Wallet API (#1960)
This commit is contained in:
parent
3f623e0c9d
commit
22ee405d18
62
Cargo.lock
generated
62
Cargo.lock
generated
@ -85,9 +85,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aligned"
|
name = "aligned"
|
||||||
version = "0.4.2"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923"
|
checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"as-slice",
|
"as-slice",
|
||||||
]
|
]
|
||||||
@ -1709,7 +1709,7 @@ dependencies = [
|
|||||||
"nomos-tracing-service",
|
"nomos-tracing-service",
|
||||||
"nomos-utils",
|
"nomos-utils",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_path_to_error",
|
"serde_path_to_error",
|
||||||
@ -1994,7 +1994,7 @@ dependencies = [
|
|||||||
"nomos-core",
|
"nomos-core",
|
||||||
"nomos-da-messages",
|
"nomos-da-messages",
|
||||||
"nomos-http-api-common",
|
"nomos-http-api-common",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
@ -3182,7 +3182,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"nomos-core",
|
"nomos-core",
|
||||||
"nomos-http-api-common",
|
"nomos-http-api-common",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4346,7 +4346,7 @@ dependencies = [
|
|||||||
"rgb",
|
"rgb",
|
||||||
"tiff",
|
"tiff",
|
||||||
"zune-core 0.5.0",
|
"zune-core 0.5.0",
|
||||||
"zune-jpeg 0.5.6",
|
"zune-jpeg 0.5.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5283,13 +5283,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.10"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
|
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall 0.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5603,9 +5603,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moxcms"
|
name = "moxcms"
|
||||||
version = "0.7.10"
|
version = "0.7.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80986bbbcf925ebd3be54c26613d861255284584501595cf418320c078945608"
|
checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"pxfm",
|
"pxfm",
|
||||||
@ -5929,7 +5929,7 @@ dependencies = [
|
|||||||
"nomos-sdp",
|
"nomos-sdp",
|
||||||
"nomos-storage",
|
"nomos-storage",
|
||||||
"overwatch",
|
"overwatch",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"subnetworks-assignations",
|
"subnetworks-assignations",
|
||||||
@ -6101,7 +6101,14 @@ name = "nomos-c"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
|
"chain-service",
|
||||||
|
"cryptarchia-engine",
|
||||||
|
"key-management-system-keys",
|
||||||
|
"nomos-api",
|
||||||
|
"nomos-core",
|
||||||
"nomos-node",
|
"nomos-node",
|
||||||
|
"nomos-wallet",
|
||||||
|
"num-bigint",
|
||||||
"overwatch",
|
"overwatch",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -6117,7 +6124,7 @@ dependencies = [
|
|||||||
"kzgrs-backend",
|
"kzgrs-backend",
|
||||||
"nomos-core",
|
"nomos-core",
|
||||||
"nomos-tracing",
|
"nomos-tracing",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -6587,7 +6594,7 @@ dependencies = [
|
|||||||
"opentelemetry-semantic-conventions",
|
"opentelemetry-semantic-conventions",
|
||||||
"opentelemetry_sdk",
|
"opentelemetry_sdk",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -6979,7 +6986,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"http 1.4.0",
|
"http 1.4.0",
|
||||||
"opentelemetry",
|
"opentelemetry",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -7167,7 +7174,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall 0.5.18",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
@ -8334,6 +8341,15 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@ -8461,9 +8477,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.25"
|
version = "0.12.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a"
|
checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -10057,7 +10073,7 @@ dependencies = [
|
|||||||
"nomos-wallet",
|
"nomos-wallet",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
@ -10604,7 +10620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ba3beec919fbdf99d719de8eda6adae3281f8a5b71ae40431f44dc7423053d34"
|
checksum = "ba3beec919fbdf99d719de8eda6adae3281f8a5b71ae40431f44dc7423053d34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"loki-api",
|
"loki-api",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"snap",
|
"snap",
|
||||||
@ -11040,7 +11056,7 @@ dependencies = [
|
|||||||
"axum",
|
"axum",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest 0.12.25",
|
"reqwest 0.12.26",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -12297,9 +12313,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-jpeg"
|
name = "zune-jpeg"
|
||||||
version = "0.5.6"
|
version = "0.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f520eebad972262a1dde0ec455bce4f8b298b1e5154513de58c114c4c54303e8"
|
checksum = "51d915729b0e7d5fe35c2f294c5dc10b30207cc637920e5b59077bfa3da63f28"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zune-core 0.5.0",
|
"zune-core 0.5.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -10,10 +10,17 @@ repository = { workspace = true }
|
|||||||
version = { workspace = true }
|
version = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nomos-node = { default-features = true, workspace = true }
|
chain-service = { workspace = true }
|
||||||
overwatch = { workspace = true }
|
cryptarchia-engine = { workspace = true }
|
||||||
serde_yaml = { default-features = false, workspace = true }
|
key-management-system-keys = { workspace = true }
|
||||||
tokio = { default-features = false, features = ["rt-multi-thread"], workspace = true }
|
nomos-api = { workspace = true }
|
||||||
|
nomos-core = { workspace = true }
|
||||||
|
nomos-node = { default-features = true, workspace = true }
|
||||||
|
nomos-wallet = { workspace = true }
|
||||||
|
num-bigint = { version = "0.4", default-features = false }
|
||||||
|
overwatch = { workspace = true }
|
||||||
|
serde_yaml = { default-features = false, workspace = true }
|
||||||
|
tokio = { default-features = false, features = ["rt-multi-thread"], workspace = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen = "0.29"
|
cbindgen = "0.29"
|
||||||
|
|||||||
125
nomos-c/src/api/cryptarchia.rs
Normal file
125
nomos-c/src/api/cryptarchia.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use crate::{
|
||||||
|
NomosNode,
|
||||||
|
api::{PointerResult, free},
|
||||||
|
errors::OperationStatus,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum State {
|
||||||
|
Bootstrapping = 0x0,
|
||||||
|
Online = 0x1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<cryptarchia_engine::State> for State {
|
||||||
|
fn from(value: cryptarchia_engine::State) -> Self {
|
||||||
|
match value {
|
||||||
|
cryptarchia_engine::State::Bootstrapping => Self::Bootstrapping,
|
||||||
|
cryptarchia_engine::State::Online => Self::Online,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Hash = [u8; 32];
|
||||||
|
pub type HeaderId = Hash;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CryptarchiaInfo {
|
||||||
|
pub lib: HeaderId,
|
||||||
|
pub tip: HeaderId,
|
||||||
|
pub slot: u64,
|
||||||
|
pub height: u64,
|
||||||
|
pub mode: State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<chain_service::CryptarchiaInfo> for CryptarchiaInfo {
|
||||||
|
fn from(value: chain_service::CryptarchiaInfo) -> Self {
|
||||||
|
Self {
|
||||||
|
lib: value.lib.into(),
|
||||||
|
tip: value.tip.into(),
|
||||||
|
slot: u64::from(value.slot),
|
||||||
|
height: value.height,
|
||||||
|
mode: State::from(value.mode),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the current Cryptarchia info.
|
||||||
|
///
|
||||||
|
/// This is a synchronous wrapper around the asynchronous
|
||||||
|
/// [`cryptarchia_info`](nomos_api::http::consensus::cryptarchia_info) function.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A [`NomosNode`] instance.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing the [`CryptarchiaInfo`] on success, or an
|
||||||
|
/// [`OperationStatus`] error on failure.
|
||||||
|
pub(crate) fn get_cryptarchia_info_sync(
|
||||||
|
node: &NomosNode,
|
||||||
|
) -> Result<chain_service::CryptarchiaInfo, OperationStatus> {
|
||||||
|
let Ok(runtime) = tokio::runtime::Runtime::new() else {
|
||||||
|
eprintln!("[get_cryptarchia_info_sync] Failed to create tokio runtime. Aborting.");
|
||||||
|
return Err(OperationStatus::RuntimeError);
|
||||||
|
};
|
||||||
|
let Ok(cryptarchia_info) = runtime.block_on(nomos_api::http::consensus::cryptarchia_info(
|
||||||
|
node.get_overwatch_handle(),
|
||||||
|
)) else {
|
||||||
|
eprintln!("[get_cryptarchia_info_sync] Failed to get cryptarchia info. Aborting.");
|
||||||
|
return Err(OperationStatus::RelayError);
|
||||||
|
};
|
||||||
|
Ok(cryptarchia_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CryptarchiaInfoResult = PointerResult<CryptarchiaInfo, OperationStatus>;
|
||||||
|
|
||||||
|
/// Get the current Cryptarchia info.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A non-null pointer to a [`NomosNode`].
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A [`CryptarchiaInfoResult`] containing a pointer to the allocated
|
||||||
|
/// [`CryptarchiaInfo`] struct on success, or an [`OperationStatus`] error on
|
||||||
|
/// failure.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is unsafe because it dereferences raw pointers.
|
||||||
|
/// The caller must ensure that all pointers are non-null and point to valid
|
||||||
|
/// memory.
|
||||||
|
///
|
||||||
|
/// # Memory Management
|
||||||
|
///
|
||||||
|
/// This function allocates memory for the output [`CryptarchiaInfo`] struct.
|
||||||
|
/// The caller must free this memory using the [`free_cryptarchia_info`]
|
||||||
|
/// function.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn get_cryptarchia_info(node: *const NomosNode) -> CryptarchiaInfoResult {
|
||||||
|
if node.is_null() {
|
||||||
|
eprintln!("[get_cryptarchia_info] Received a null `node` pointer. Exiting.");
|
||||||
|
return CryptarchiaInfoResult::from_error(OperationStatus::NullPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let node = unsafe { &*node };
|
||||||
|
match get_cryptarchia_info_sync(node) {
|
||||||
|
Ok(cryptarchia_info) => {
|
||||||
|
let cryptarchia_info = CryptarchiaInfo::from(cryptarchia_info);
|
||||||
|
CryptarchiaInfoResult::from_value(cryptarchia_info)
|
||||||
|
}
|
||||||
|
Err(error) => CryptarchiaInfoResult::from_error(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees the memory allocated for a [`CryptarchiaInfo`] struct.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `pointer`: A pointer to the [`CryptarchiaInfo`] struct to be freed.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn free_cryptarchia_info(pointer: *mut CryptarchiaInfo) {
|
||||||
|
free::<CryptarchiaInfo>(pointer);
|
||||||
|
}
|
||||||
@ -3,31 +3,40 @@ use std::ffi::c_char;
|
|||||||
use nomos_node::{Config, get_services_to_start, run_node_from_config};
|
use nomos_node::{Config, get_services_to_start, run_node_from_config};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use crate::{NomosNode, errors::NomosNodeErrorCode};
|
use crate::{NomosNode, api::PointerResult, errors::NomosNodeErrorCode};
|
||||||
|
|
||||||
#[repr(C)]
|
pub type InitializedNomosNodeResult = PointerResult<NomosNode, NomosNodeErrorCode>;
|
||||||
pub struct InitializedNomosNodeResult {
|
|
||||||
nomos_node: *mut NomosNode,
|
|
||||||
error_code: NomosNodeErrorCode,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// Creates and starts a Nomos node based on the provided configuration file
|
||||||
|
/// path.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `config_path`: A pointer to a string representing the path to the
|
||||||
|
/// configuration file.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// An `InitializedNomosNodeResult` containing either a pointer to the
|
||||||
|
/// initialized `NomosNode` or an error code.
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn start_nomos_node(config_path: *const c_char) -> InitializedNomosNodeResult {
|
pub extern "C" fn start_nomos_node(config_path: *const c_char) -> InitializedNomosNodeResult {
|
||||||
match initialize_nomos_node(config_path) {
|
initialize_nomos_node(config_path).map_or_else(
|
||||||
Ok(nomos_node) => {
|
InitializedNomosNodeResult::from_error,
|
||||||
let node_ptr = Box::into_raw(Box::new(nomos_node));
|
InitializedNomosNodeResult::from_value,
|
||||||
InitializedNomosNodeResult {
|
)
|
||||||
nomos_node: node_ptr,
|
|
||||||
error_code: NomosNodeErrorCode::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(error_code) => InitializedNomosNodeResult {
|
|
||||||
nomos_node: core::ptr::null_mut(),
|
|
||||||
error_code,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/// Initializes and starts a Nomos node based on the provided configuration file
|
||||||
|
/// path.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `config_path`: A pointer to a string representing the path to the
|
||||||
|
/// configuration file.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing either the initialized `NomosNode` or an error code.
|
||||||
fn initialize_nomos_node(config_path: *const c_char) -> Result<NomosNode, NomosNodeErrorCode> {
|
fn initialize_nomos_node(config_path: *const c_char) -> Result<NomosNode, NomosNodeErrorCode> {
|
||||||
// TODO: Remove flags when dynamic run of services is implemented.
|
// TODO: Remove flags when dynamic run of services is implemented.
|
||||||
let must_blend_service_group_start = true;
|
let must_blend_service_group_start = true;
|
||||||
@ -79,13 +88,23 @@ fn initialize_nomos_node(config_path: *const c_char) -> Result<NomosNode, NomosN
|
|||||||
Ok(NomosNode::new(app, rt))
|
Ok(NomosNode::new(app, rt))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
/// Stops and frees the resources associated with the given Nomos node.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A pointer to the `NomosNode` instance to be stopped.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// An `NomosNodeErrorCode` indicating success or failure.
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// The caller must ensure that:
|
/// The caller must ensure that:
|
||||||
/// - `node` is a valid pointer to a `NomosNode` instance
|
/// - `node` is a valid pointer to a `NomosNode` instance
|
||||||
/// - The `NomosNode` instance was created by this library
|
/// - The `NomosNode` instance was created by this library
|
||||||
/// - The pointer will not be used after this function returns
|
/// - The pointer will not be used after this function returns
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn stop_node(node: *mut NomosNode) -> NomosNodeErrorCode {
|
pub unsafe extern "C" fn stop_node(node: *mut NomosNode) -> NomosNodeErrorCode {
|
||||||
if node.is_null() {
|
if node.is_null() {
|
||||||
eprintln!("Attempted to stop a null node pointer. This is a bug. Aborting.");
|
eprintln!("Attempted to stop a null node pointer. This is a bug. Aborting.");
|
||||||
|
|||||||
12
nomos-c/src/api/memory.rs
Normal file
12
nomos-c/src/api/memory.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/// Frees memory allocated for a given pointer.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `pointer` - A pointer to the memory to be freed.
|
||||||
|
pub fn free<Type>(pointer: *mut Type) {
|
||||||
|
if !pointer.is_null() {
|
||||||
|
unsafe {
|
||||||
|
drop(Box::from_raw(pointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1,8 @@
|
|||||||
|
pub mod cryptarchia;
|
||||||
pub mod lifecycle;
|
pub mod lifecycle;
|
||||||
|
pub(crate) mod memory;
|
||||||
|
pub(crate) mod result;
|
||||||
|
pub mod wallet;
|
||||||
|
|
||||||
|
pub(crate) use memory::free;
|
||||||
|
pub(crate) use result::{PointerResult, ValueResult};
|
||||||
|
|||||||
55
nomos-c/src/api/result.rs
Normal file
55
nomos-c/src/api/result.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/// Simple wrapper around a value or an error.
|
||||||
|
///
|
||||||
|
/// Value is not guaranteed. You should check the error field before accessing
|
||||||
|
/// the value.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ValueResult<Type, Error> {
|
||||||
|
pub value: Type,
|
||||||
|
pub error: Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Type: Default, Error: Default> ValueResult<Type, Error> {
|
||||||
|
pub fn from_value(value: Type) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
error: Error::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_error(error: Error) -> Self {
|
||||||
|
Self {
|
||||||
|
value: Type::default(),
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simple wrapper around a pointer to a value or an error.
|
||||||
|
///
|
||||||
|
/// Pointer is not guaranteed. You should check the error field before
|
||||||
|
/// dereferencing the pointer.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PointerResult<Type, Error> {
|
||||||
|
pub value: *mut Type,
|
||||||
|
pub error: Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Type, Error: Default> PointerResult<Type, Error> {
|
||||||
|
pub fn from_pointer(pointer: *mut Type) -> Self {
|
||||||
|
Self {
|
||||||
|
value: pointer,
|
||||||
|
error: Error::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_value(value: Type) -> Self {
|
||||||
|
Self::from_pointer(Box::into_raw(Box::new(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_error(error: Error) -> Self {
|
||||||
|
Self {
|
||||||
|
value: std::ptr::null_mut(),
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
326
nomos-c/src/api/wallet.rs
Normal file
326
nomos-c/src/api/wallet.rs
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
use key_management_system_keys::keys::ZkPublicKey;
|
||||||
|
use nomos_core::mantle::{SignedMantleTx, Transaction as _, Value};
|
||||||
|
use nomos_wallet::{WalletService, api::WalletApi};
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
NomosNode,
|
||||||
|
api::{
|
||||||
|
ValueResult,
|
||||||
|
cryptarchia::{Hash, HeaderId, get_cryptarchia_info_sync},
|
||||||
|
free,
|
||||||
|
},
|
||||||
|
errors::OperationStatus,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get the balance of a wallet address
|
||||||
|
///
|
||||||
|
/// This is a synchronous wrapper around [`WalletApi::get_balance`].
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A [`NomosNode`] instance.
|
||||||
|
/// - `tip`: The header ID to query the balance at.
|
||||||
|
/// - `wallet_address`: The public key of the wallet address to query.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing an [`Option<Value>`] on success, or an
|
||||||
|
/// [`OperationStatus`] error on failure.
|
||||||
|
pub(crate) fn get_balance_sync(
|
||||||
|
node: &NomosNode,
|
||||||
|
tip: nomos_core::header::HeaderId,
|
||||||
|
wallet_address: ZkPublicKey,
|
||||||
|
) -> Result<Option<Value>, OperationStatus> {
|
||||||
|
let Ok(runtime) = tokio::runtime::Runtime::new() else {
|
||||||
|
eprintln!("[Failed]to create tokio runtime. Aborting.");
|
||||||
|
return Err(OperationStatus::RuntimeError);
|
||||||
|
};
|
||||||
|
|
||||||
|
runtime
|
||||||
|
.block_on(async {
|
||||||
|
let api = WalletApi::<WalletService<_, _, _, _, _>, _>::from_overwatch_handle(
|
||||||
|
node.get_overwatch_handle(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
api.get_balance(tip, wallet_address).await
|
||||||
|
})
|
||||||
|
.map_err(|_| OperationStatus::DynError)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BalanceResult = ValueResult<Value, OperationStatus>;
|
||||||
|
|
||||||
|
/// Get the balance of a wallet address
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A non-null pointer to a [`NomosNode`] instance.
|
||||||
|
/// - `wallet_address`: A non-null pointer to the public key bytes of the wallet
|
||||||
|
/// address to query.
|
||||||
|
/// - `optional_tip`: An optional pointer to the header ID to query the balance
|
||||||
|
/// at. If null, the current tip will be used.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A [`ValueResult`] containing the balance on success, or an
|
||||||
|
/// [`OperationStatus`] error on failure.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is unsafe because it dereferences raw pointers. The caller
|
||||||
|
/// must ensure that all pointers are valid.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn get_balance(
|
||||||
|
node: *const NomosNode,
|
||||||
|
wallet_address: *const u8,
|
||||||
|
optional_tip: *const HeaderId,
|
||||||
|
) -> BalanceResult {
|
||||||
|
if node.is_null() {
|
||||||
|
eprintln!("[get_balance] Received a null `node` pointer. Exiting.");
|
||||||
|
return BalanceResult::from_error(OperationStatus::NullPtr);
|
||||||
|
}
|
||||||
|
if wallet_address.is_null() {
|
||||||
|
eprintln!("[get_balance] Received a null `wallet_address` pointer. Exiting.");
|
||||||
|
return BalanceResult::from_error(OperationStatus::NullPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let node = unsafe { &*node };
|
||||||
|
let tip = if optional_tip.is_null() {
|
||||||
|
match get_cryptarchia_info_sync(node) {
|
||||||
|
Ok(cryptarchia_info) => cryptarchia_info.tip,
|
||||||
|
Err(error) => return BalanceResult::from_error(error),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nomos_core::header::HeaderId::from(unsafe { *optional_tip })
|
||||||
|
};
|
||||||
|
let wallet_address_bytes = unsafe { std::slice::from_raw_parts(wallet_address, 32) };
|
||||||
|
let wallet_address = ZkPublicKey::from(BigUint::from_bytes_le(wallet_address_bytes));
|
||||||
|
|
||||||
|
match get_balance_sync(node, tip, wallet_address) {
|
||||||
|
Ok(Some(balance)) => BalanceResult::from_value(balance),
|
||||||
|
Ok(None) => BalanceResult::from_error(OperationStatus::NotFound),
|
||||||
|
Err(status) => BalanceResult::from_error(status),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TransferFundsArguments {
|
||||||
|
pub optional_tip: *const HeaderId,
|
||||||
|
pub change_public_key: *const u8,
|
||||||
|
pub funding_public_keys: *const *const u8,
|
||||||
|
pub funding_public_keys_len: usize,
|
||||||
|
pub recipient_public_key: *const u8,
|
||||||
|
pub amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransferFundsArguments {
|
||||||
|
/// Validates the arguments of the [`TransferFundsArguments`] struct.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` indicating success or containing an error message and status.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is unsafe because it dereferences raw pointers. The caller
|
||||||
|
/// must ensure that all pointers are valid.
|
||||||
|
pub unsafe fn validate(&self) -> Result<(), (String, OperationStatus)> {
|
||||||
|
if self.change_public_key.is_null() {
|
||||||
|
return Err((
|
||||||
|
"TransferFunds contains a null `change_public_key` pointer.".to_owned(),
|
||||||
|
OperationStatus::NullPtr,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.funding_public_keys.is_null() {
|
||||||
|
return Err((
|
||||||
|
"TransferFunds contains a null `funding_public_keys` pointer.".to_owned(),
|
||||||
|
OperationStatus::NullPtr,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..self.funding_public_keys_len {
|
||||||
|
let funding_public_key_pointer = unsafe { self.funding_public_keys.add(i) };
|
||||||
|
let funding_public_key = unsafe { *funding_public_key_pointer };
|
||||||
|
if funding_public_key.is_null() {
|
||||||
|
let error_message =
|
||||||
|
format!("TransferFunds contains a null pointer at `funding_public_keys[{i}]`.");
|
||||||
|
return Err((error_message, OperationStatus::NullPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.recipient_public_key.is_null() {
|
||||||
|
return Err((
|
||||||
|
"TransferFunds contains a null `recipient_public_key` pointer.".to_owned(),
|
||||||
|
OperationStatus::NullPtr,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transfer funds from some addresses to another.
|
||||||
|
///
|
||||||
|
/// This is a synchronous wrapper around [`WalletApi::transfer_funds`].
|
||||||
|
///
|
||||||
|
/// This function does not validate the arguments. It assumes they have already
|
||||||
|
/// been validated.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A [`NomosNode`] instance.
|
||||||
|
/// - `tip`: The header ID at which to perform the transfer.
|
||||||
|
/// - `change_public_key`: The public key to receive any change from the
|
||||||
|
/// transaction.
|
||||||
|
/// - `funding_public_keys`: A vector of public keys to fund the transaction.
|
||||||
|
/// - `recipient_public_key`: The public key of the recipient.
|
||||||
|
/// - `amount`: The amount to transfer.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing a [`SignedMantleTx`] on success, or an
|
||||||
|
/// [`OperationStatus`] error on failure.
|
||||||
|
pub(crate) fn transfer_funds_sync(
|
||||||
|
node: &NomosNode,
|
||||||
|
tip: nomos_core::header::HeaderId,
|
||||||
|
change_public_key: ZkPublicKey,
|
||||||
|
funding_public_keys: Vec<ZkPublicKey>,
|
||||||
|
recipient_public_key: ZkPublicKey,
|
||||||
|
amount: u64,
|
||||||
|
) -> Result<SignedMantleTx, OperationStatus> {
|
||||||
|
let Ok(runtime) = tokio::runtime::Runtime::new() else {
|
||||||
|
eprintln!("[transfer_funds_sync] Failed to create tokio runtime. Aborting.");
|
||||||
|
return Err(OperationStatus::RuntimeError);
|
||||||
|
};
|
||||||
|
|
||||||
|
runtime
|
||||||
|
.block_on(async {
|
||||||
|
let api = WalletApi::<WalletService<_, _, _, _, _>, _>::from_overwatch_handle(
|
||||||
|
node.get_overwatch_handle(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
api.transfer_funds(
|
||||||
|
tip,
|
||||||
|
change_public_key,
|
||||||
|
funding_public_keys,
|
||||||
|
recipient_public_key,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
.map_err(|_| OperationStatus::DynError)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TransferFundsResult = ValueResult<Hash, OperationStatus>;
|
||||||
|
|
||||||
|
/// Transfer funds from some addresses to another.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `node`: A non-null pointer to a [`NomosNode`] instance.
|
||||||
|
/// - `arguments`: A non-null pointer to a [`TransferFundsArguments`] struct
|
||||||
|
/// containing the transaction arguments.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A [`TransferFundsResult`] containing a pointer to a [`Hash`] where the
|
||||||
|
/// transaction hash will be written on success, or an [`OperationStatus`] error
|
||||||
|
/// on failure. The hash will be written in little-endian format.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is unsafe because it dereferences raw pointers. The caller
|
||||||
|
/// must ensure that all pointers are valid.
|
||||||
|
///
|
||||||
|
/// # Memory Management
|
||||||
|
///
|
||||||
|
/// This function allocates memory for the output [`CryptarchiaInfo`] struct.
|
||||||
|
/// The caller must free this memory using the [`free_cryptarchia_info`]
|
||||||
|
/// function.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn transfer_funds(
|
||||||
|
node: *const NomosNode,
|
||||||
|
arguments: *const TransferFundsArguments,
|
||||||
|
) -> TransferFundsResult {
|
||||||
|
if node.is_null() {
|
||||||
|
eprintln!("[transfer_funds] Received a null `node` pointer. Exiting.");
|
||||||
|
return TransferFundsResult::from_error(OperationStatus::NullPtr);
|
||||||
|
}
|
||||||
|
if arguments.is_null() {
|
||||||
|
eprintln!("[transfer_funds] Received a null `arguments` pointer. Exiting.");
|
||||||
|
return TransferFundsResult::from_error(OperationStatus::NullPtr);
|
||||||
|
}
|
||||||
|
let arguments = unsafe { &*arguments };
|
||||||
|
if let Err((error_message, status)) = unsafe { arguments.validate() } {
|
||||||
|
eprintln!("[transfer_funds] {error_message} Exiting.");
|
||||||
|
return TransferFundsResult::from_error(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
let node = unsafe { &*node };
|
||||||
|
let tip = if arguments.optional_tip.is_null() {
|
||||||
|
match get_cryptarchia_info_sync(node) {
|
||||||
|
Ok(cryptarchia_info) => cryptarchia_info.tip,
|
||||||
|
Err(status) => {
|
||||||
|
eprintln!("[transfer_funds] Failed to get cryptarchia info. Aborting.");
|
||||||
|
return TransferFundsResult::from_error(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nomos_core::header::HeaderId::from(unsafe { *arguments.optional_tip })
|
||||||
|
};
|
||||||
|
let change_public_key = {
|
||||||
|
let change_public_key_bytes =
|
||||||
|
unsafe { std::slice::from_raw_parts(arguments.change_public_key, 32) };
|
||||||
|
ZkPublicKey::from(BigUint::from_bytes_le(change_public_key_bytes))
|
||||||
|
};
|
||||||
|
let funding_public_keys = {
|
||||||
|
let funding_public_keys_pointers = unsafe {
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
arguments.funding_public_keys,
|
||||||
|
arguments.funding_public_keys_len,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
funding_public_keys_pointers
|
||||||
|
.iter()
|
||||||
|
.map(|funding_public_key_pointer| {
|
||||||
|
let funding_public_key_bytes =
|
||||||
|
unsafe { std::slice::from_raw_parts(*funding_public_key_pointer, 32) };
|
||||||
|
ZkPublicKey::from(BigUint::from_bytes_le(funding_public_key_bytes))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
let recipient_public_key = {
|
||||||
|
let recipient_public_key_bytes =
|
||||||
|
unsafe { std::slice::from_raw_parts(arguments.recipient_public_key, 32) };
|
||||||
|
ZkPublicKey::from(BigUint::from_bytes_le(recipient_public_key_bytes))
|
||||||
|
};
|
||||||
|
let amount = Value::from(arguments.amount);
|
||||||
|
|
||||||
|
match transfer_funds_sync(
|
||||||
|
node,
|
||||||
|
tip,
|
||||||
|
change_public_key,
|
||||||
|
funding_public_keys,
|
||||||
|
recipient_public_key,
|
||||||
|
amount,
|
||||||
|
) {
|
||||||
|
Ok(transaction) => {
|
||||||
|
let transaction_hash = transaction.hash().as_signing_bytes();
|
||||||
|
let Ok(transaction_hash_array) = transaction_hash.iter().as_slice().try_into() else {
|
||||||
|
eprintln!("[transfer_funds] Failed to convert transaction hash to array. Exiting.");
|
||||||
|
return TransferFundsResult::from_error(OperationStatus::RuntimeError);
|
||||||
|
};
|
||||||
|
TransferFundsResult::from_value(transaction_hash_array)
|
||||||
|
}
|
||||||
|
Err(status) => TransferFundsResult::from_error(status),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees the memory allocated for a [`Hash`] value.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `pointer`: A pointer to the [`Hash`] to be freed.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn free_transfer_funds(pointer: *mut Hash) {
|
||||||
|
free::<Hash>(pointer);
|
||||||
|
}
|
||||||
@ -1,7 +1,30 @@
|
|||||||
#[repr(u8)]
|
#[derive(Default)]
|
||||||
|
#[repr(C)]
|
||||||
pub enum NomosNodeErrorCode {
|
pub enum NomosNodeErrorCode {
|
||||||
|
#[default]
|
||||||
None = 0x0,
|
None = 0x0,
|
||||||
CouldNotInitialize = 0x1,
|
CouldNotInitialize = 0x1,
|
||||||
StopError = 0x2,
|
StopError = 0x2,
|
||||||
NullPtr = 0x3,
|
NullPtr = 0x3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum OperationStatus {
|
||||||
|
#[default]
|
||||||
|
Ok = 0x0,
|
||||||
|
NotFound = 0x1,
|
||||||
|
NullPtr = 0x2,
|
||||||
|
RelayError = 0x3,
|
||||||
|
ChannelSendError = 0x4,
|
||||||
|
ChannelReceiveError = 0x5,
|
||||||
|
ServiceError = 0x6,
|
||||||
|
RuntimeError = 0x7,
|
||||||
|
DynError = 0x8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OperationStatus {
|
||||||
|
pub fn is_ok(&self) -> bool {
|
||||||
|
*self == Self::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ impl NomosNode {
|
|||||||
|
|
||||||
// Helper methods to safely access the inner types
|
// Helper methods to safely access the inner types
|
||||||
#[must_use]
|
#[must_use]
|
||||||
const fn get_overwatch_handle(&self) -> &OverwatchHandle<RuntimeServiceId> {
|
pub(crate) const fn get_overwatch_handle(&self) -> &OverwatchHandle<RuntimeServiceId> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.overwatch
|
self.overwatch
|
||||||
.cast::<NomosOverwatch>()
|
.cast::<NomosOverwatch>()
|
||||||
@ -39,7 +39,7 @@ impl NomosNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn get_runtime_handle(&self) -> &Handle {
|
pub(crate) fn get_runtime_handle(&self) -> &Handle {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.runtime
|
self.runtime
|
||||||
.cast::<Runtime>()
|
.cast::<Runtime>()
|
||||||
|
|||||||
@ -5,11 +5,12 @@ use nomos_core::{
|
|||||||
};
|
};
|
||||||
use overwatch::{
|
use overwatch::{
|
||||||
DynError,
|
DynError,
|
||||||
|
overwatch::OverwatchHandle,
|
||||||
services::{AsServiceId, ServiceData, relay::OutboundRelay},
|
services::{AsServiceId, ServiceData, relay::OutboundRelay},
|
||||||
};
|
};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
use crate::{WalletMsg, WalletServiceSettings};
|
use crate::{WalletMsg, WalletService, WalletServiceSettings};
|
||||||
|
|
||||||
pub trait WalletServiceData:
|
pub trait WalletServiceData:
|
||||||
ServiceData<Settings = WalletServiceSettings, Message = WalletMsg>
|
ServiceData<Settings = WalletServiceSettings, Message = WalletMsg>
|
||||||
@ -21,7 +22,7 @@ pub trait WalletServiceData:
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Kms, Cryptarchia, Tx, Storage, RuntimeServiceId> WalletServiceData
|
impl<Kms, Cryptarchia, Tx, Storage, RuntimeServiceId> WalletServiceData
|
||||||
for crate::WalletService<Kms, Cryptarchia, Tx, Storage, RuntimeServiceId>
|
for WalletService<Kms, Cryptarchia, Tx, Storage, RuntimeServiceId>
|
||||||
{
|
{
|
||||||
type Kms = Kms;
|
type Kms = Kms;
|
||||||
type Cryptarchia = Cryptarchia;
|
type Cryptarchia = Cryptarchia;
|
||||||
@ -50,6 +51,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub async fn from_overwatch_handle(handle: &OverwatchHandle<RuntimeServiceId>) -> Self {
|
||||||
|
let relay = handle.relay::<Wallet>().await.unwrap();
|
||||||
|
Self::new(relay)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_balance(
|
pub async fn get_balance(
|
||||||
&self,
|
&self,
|
||||||
tip: HeaderId,
|
tip: HeaderId,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user