From 76010923736edb478eeb46dc728728239beb1bf0 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 19 Mar 2021 19:27:42 +0100 Subject: [PATCH] Returning detailed validation status --- Cargo.lock | 15 ++++---- Cargo.toml | 4 +- citadel.h | 21 ++++++++++- src/capi/rpc.rs | 14 +++---- src/capi/types.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 1 + 6 files changed, 129 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb63da8..1d91a56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -339,9 +339,10 @@ dependencies = [ ] [[package]] -name = "citadel" -version = "0.1.0-rc" -source = "git+https://github.com/mycitadel/citadel-runtime#780382917348422ea1267f5066d335d197b9363d" +name = "citadel-runtime" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803469364b0fabcffee51c7c5a7254f7cf2ef8487d86faa090616c44055efb89" dependencies = [ "amplify", "amplify_derive", @@ -999,7 +1000,7 @@ checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" [[package]] name = "libcitadel" -version = "0.1.0-rc" +version = "0.1.0" dependencies = [ "amplify", "amplify_derive", @@ -1009,7 +1010,7 @@ dependencies = [ "bip39", "bitcoin", "cbindgen", - "citadel", + "citadel-runtime", "descriptor-wallet", "env_logger", "internet2", @@ -1778,9 +1779,9 @@ dependencies = [ [[package]] name = "rgb_node" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615e0bb88f1a94c3a2cc927ae882275bed80997430eec9ffc904060945551abd" +checksum = "a9e4c0506094221f4134bb92ee73385f661e71540209c57bf80305411bd5d1af" dependencies = [ "amplify", "amplify_derive", diff --git a/Cargo.toml b/Cargo.toml index 3eb2760..77e5252 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libcitadel" -version = "0.1.0-rc" +version = "0.1.0" description = "C-language bindings for Citadel runtime" authors = ["Dr Maxim Orlovsky "] license = "MIT" @@ -19,7 +19,7 @@ openssl = { version = "^0.10", features = ["vendored"] } libc = "0.2" amplify = "3" amplify_derive = "2.4" -citadel = { git = "https://github.com/mycitadel/citadel-runtime" } +citadel-runtime = "0.1" # slip132 = "0.3.2" lnpbp = "0.4" lnpbp-invoice = { version = "0.1.0", features = ["serde", "rgb"] } diff --git a/citadel.h b/citadel.h index 9b7674f..f55295a 100644 --- a/citadel.h +++ b/citadel.h @@ -157,6 +157,13 @@ typedef enum invoice_type { INVOICE_TYPE_PSBT, } invoice_type; +typedef enum validity_t { + VALIDITY_T_UNABLE_TO_VALIDATE, + VALIDITY_T_VALID, + VALIDITY_T_UNRESOLVED_TX, + VALIDITY_T_INVALID, +} validity_t; + typedef struct bech32_info_t { int status; int category; @@ -186,6 +193,16 @@ typedef struct prepared_transfer_t { const char *psbt_base64; } prepared_transfer_t; +typedef struct validation_status_t { + enum validity_t validity; + uint32_t info_len; + const char *const *info; + uint32_t warn_len; + const char *const *warn; + uint32_t failures_len; + const char *const *failures; +} validation_status_t; + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -262,8 +279,8 @@ struct prepared_transfer_t citadel_invoice_pay(struct citadel_client_t *client, const char *citadel_psbt_publish(struct citadel_client_t *client, const char *psbt); -const char *citadel_invoice_accept(struct citadel_client_t *client, - const char *consignment); +struct validation_status_t citadel_invoice_accept(struct citadel_client_t *client, + const char *consignment); const char *citadel_asset_list(struct citadel_client_t *client); diff --git a/src/capi/rpc.rs b/src/capi/rpc.rs index 148c0dd..8b4eafc 100644 --- a/src/capi/rpc.rs +++ b/src/capi/rpc.rs @@ -26,7 +26,7 @@ use wallet::bip32::PubkeyChain; use wallet::Psbt; use super::{descriptor_type, invoice_type}; -use crate::capi::{prepared_transfer_t, AddressInfo}; +use crate::capi::{prepared_transfer_t, AddressInfo, validation_status_t}; use crate::citadel_client_t; use crate::error::*; use crate::helpers::{TryAsStr, TryIntoRaw}; @@ -454,18 +454,18 @@ pub extern "C" fn citadel_psbt_publish( pub extern "C" fn citadel_invoice_accept( client: *mut citadel_client_t, consignment: *const c_char, -) -> *const c_char { +) -> validation_status_t { let client = citadel_client_t::from_raw(client); let consignment = match client.parse_string(consignment, "consignment").ok() { - None => return ptr::null(), + None => return validation_status_t::failure(), Some(v) => v, }; let consignment = match Consignment::from_str(&consignment) { Err(err) => { client.set_error_details(ERRNO_PARSE, err); - return ptr::null(); + return validation_status_t::failure(); } Ok(v) => v, }; @@ -477,13 +477,13 @@ pub extern "C" fn citadel_invoice_accept( .map_err(|_| ()) .and_then(|res| res.ok_or(())) .ok() - .and_then(|status| status.to_string().try_into_raw()) + .map(validation_status_t::from) { client.set_success(); - return status; + return status } - return ptr::null(); + return validation_status_t::failure(); } #[no_mangle] diff --git a/src/capi/types.rs b/src/capi/types.rs index aa01ff2..6d2d1b1 100644 --- a/src/capi/types.rs +++ b/src/capi/types.rs @@ -7,17 +7,18 @@ // the public domain worldwide. This software is distributed without // any warranty. -use libc::c_char; +use libc::{c_char}; use std::ptr; use bitcoin::consensus::serialize; use citadel::client::InvoiceType; use citadel::rpc::message; use lnpbp::bech32::ToBech32String; -use rgb::Consignment; +use rgb::{Consignment, validation::{self, Validity}}; use wallet::descriptor; use crate::TryIntoRaw; +use rgb::validation::{Info, Warning, Failure}; #[allow(non_camel_case_types)] #[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -94,3 +95,92 @@ impl From for prepared_transfer_t { } } } + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[repr(C)] +pub enum validity_t { + UNABLE_TO_VALIDATE, + VALID, + UNRESOLVED_TX, + INVALID, +} + +impl From for validity_t { + fn from(validity: Validity) -> Self { + match validity { + Validity::Valid => Self::VALID, + Validity::UnresolvedTransactions => Self::UNRESOLVED_TX, + Validity::Invalid => Self::INVALID, + } + } +} + +// TODO: Provide memory release function for `prepared_transfer_t` +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct validation_status_t { + pub validity: validity_t, + pub info_len: u32, + pub info: *const *const c_char, + pub warn_len: u32, + pub warn: *const *const c_char, + pub failures_len: u32, + pub failures: *const *const c_char, +} + +impl validation_status_t { + pub fn failure() -> Self { + validation_status_t { + validity: validity_t::UNABLE_TO_VALIDATE, + info_len: 0, + info: ptr::null(), + warn_len: 0, + warn: ptr::null(), + failures_len: 0, + failures: ptr::null() + } + } +} + +impl From for validation_status_t { + fn from(status: validation::Status) -> Self { + + let mut info = status.info + .iter() + .map(Info::to_string) + .map(String::try_into_raw) + .map(Option::unwrap) + .collect::>(); + info.shrink_to_fit(); + let (info, info_len, _) = info.into_raw_parts(); + + let mut warn = status.warnings + .iter() + .map(Warning::to_string) + .map(String::try_into_raw) + .map(Option::unwrap) + .collect::>(); + warn.shrink_to_fit(); + let (warn, warn_len, _) = warn.into_raw_parts(); + + let mut failures = status.failures + .iter() + .map(Failure::to_string) + .map(String::try_into_raw) + .map(Option::unwrap) + .collect::>(); + failures.shrink_to_fit(); + let (failures, failures_len, _) = failures.into_raw_parts(); + + validation_status_t { + validity: status.validity().into(), + info_len: info_len as u32, + info, + warn_len: warn_len as u32, + warn, + failures_len: failures_len as u32, + failures + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 99a4a86..c49a362 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![recursion_limit = "256"] #![feature(try_trait)] +#![feature(vec_into_raw_parts)] // Coding conventions #![deny( non_upper_case_globals,