Skip to content

Commit

Permalink
Merge pull request #900 from breez/collect-data
Browse files Browse the repository at this point in the history
Diagnostic data for supporting users.
  • Loading branch information
roeierez authored Mar 28, 2024
2 parents d444310 + 9f49da7 commit 759c22d
Show file tree
Hide file tree
Showing 20 changed files with 236 additions and 38 deletions.
3 changes: 3 additions & 0 deletions libs/sdk-bindings/src/breez_sdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,9 @@ interface BlockingBreezServices {
[Throws=SdkError]
string execute_dev_command(string command);

[Throws=SdkError]
string generate_diagnostic_data();

[Throws=SdkError]
void sync();

Expand Down
4 changes: 4 additions & 0 deletions libs/sdk-bindings/src/uniffi_binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ impl BlockingBreezServices {
rt().block_on(self.breez_services.execute_dev_command(command))
}

pub fn generate_diagnostic_data(&self) -> SdkResult<String> {
rt().block_on(self.breez_services.generate_diagnostic_data())
}

pub fn sync(&self) -> SdkResult<()> {
rt().block_on(self.breez_services.sync())
}
Expand Down
6 changes: 6 additions & 0 deletions libs/sdk-core/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,12 @@ pub fn execute_command(command: String) -> Result<String> {
.map_err(anyhow::Error::new::<SdkError>)
}

/// See [BreezServices::generate_diagnostic_data]
pub fn generate_diagnostic_data() -> Result<String> {
block_on(async { get_breez_services().await?.generate_diagnostic_data().await })
.map_err(anyhow::Error::new::<SdkError>)
}

/* Binding Related Logic */

struct BindingEventListener;
Expand Down
34 changes: 34 additions & 0 deletions libs/sdk-core/src/breez_services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,14 @@ impl BreezServices {
Ok(self.node_api.execute_command(command).await?)
}

// Collects various user data from the node and the sdk storage.
// This is used for debugging and support purposes only.
pub async fn generate_diagnostic_data(&self) -> SdkResult<String> {
let node_data = self.node_api.generate_diagnostic_data().await?;
let sdk_data = self.generate_sdk_diagnostic_data().await?;
Ok(format!("Node Data\n{node_data}\n\nSDK Data\n{sdk_data}"))
}

/// This method sync the local state with the remote node state.
/// The synced items are as follows:
/// * node state - General information about the node and its liquidity status
Expand Down Expand Up @@ -1878,6 +1886,32 @@ impl BreezServices {
err: format!("Failed to register for tx confirmation notifications: {err}"),
})
}

async fn generate_sdk_diagnostic_data(&self) -> SdkResult<String> {
let state: String = serde_json::to_string_pretty(&self.persister.get_node_state()?)?;
let payments = serde_json::to_string_pretty(
&self
.persister
.list_payments(ListPaymentsRequest::default())?,
)?;
let channels = serde_json::to_string_pretty(&self.persister.list_channels()?)?;
let settings = serde_json::to_string_pretty(&self.persister.list_settings()?)?;
let reverse_swaps = serde_json::to_string_pretty(&self.persister.list_reverse_swaps()?)?;
let swaps = serde_json::to_string_pretty(&self.persister.list_swaps()?)?;
let lsp_id = serde_json::to_string_pretty(&self.persister.get_lsp_id()?)?;

let res = format!(
"\
***Node State***\n{state}\n\n \
***Payments***\n{payments}\n\n \
***Channels***\n{channels}\n\n \
***Settings***\n{settings}\n\n \
***Reverse Swaps***\n{reverse_swaps}\n\n \
***LSP ID***\n{lsp_id}\n\n \
***Swaps***\n{swaps}\n\n"
);
Ok(res)
}
}

struct GlobalSdkLogger {
Expand Down
5 changes: 5 additions & 0 deletions libs/sdk-core/src/bridge_generated.io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,11 @@ pub extern "C" fn wire_execute_command(port_: i64, command: *mut wire_uint_8_lis
wire_execute_command_impl(port_, command)
}

#[no_mangle]
pub extern "C" fn wire_generate_diagnostic_data(port_: i64) {
wire_generate_diagnostic_data_impl(port_)
}

// Section: allocate functions

#[no_mangle]
Expand Down
10 changes: 10 additions & 0 deletions libs/sdk-core/src/bridge_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,16 @@ fn wire_execute_command_impl(port_: MessagePort, command: impl Wire2Api<String>
},
)
}
fn wire_generate_diagnostic_data_impl(port_: MessagePort) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, String, _>(
WrapInfo {
debug_name: "generate_diagnostic_data",
port: Some(port_),
mode: FfiCallMode::Normal,
},
move || move |task_callback| generate_diagnostic_data(),
)
}
// Section: wrapper structs

// Section: static checks
Expand Down
21 changes: 21 additions & 0 deletions libs/sdk-core/src/greenlight/node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,27 @@ impl NodeAPI for Greenlight {
Ok(hex_vec)
}

async fn generate_diagnostic_data(&self) -> NodeResult<String> {
let all_commands = vec![
NodeCommand::GetInfo.to_string(),
NodeCommand::ListPeerChannels.to_string(),
NodeCommand::ListFunds.to_string(),
NodeCommand::ListPayments.to_string(),
NodeCommand::ListInvoices.to_string(),
];

let mut result = String::new();
for command in all_commands {
let command_name = command.clone();
let res = self
.execute_command(command)
.await
.unwrap_or_else(|e| e.to_string());
result += &format!("***{command_name}:***\n\n {res}\n\n");
}
Ok(result)
}

async fn execute_command(&self, command: String) -> NodeResult<String> {
let node_cmd =
NodeCommand::from_str(&command).map_err(|_| anyhow!("Command not found: {command}"))?;
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-core/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,7 @@ impl OpeningFeeParamsMenu {
}

/// Lightning channel
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
pub struct Channel {
pub funding_txid: String,
pub short_channel_id: Option<String>,
Expand All @@ -1265,7 +1265,7 @@ pub struct Channel {
pub htlcs: Vec<Htlc>,
}

#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
pub struct Htlc {
pub expiry: u32,
pub payment_hash: Vec<u8>,
Expand Down
17 changes: 9 additions & 8 deletions libs/sdk-core/src/node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ use tonic::Streaming;

use crate::{
bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey},
invoice::InvoiceError, lightning_invoice::RawBolt11Invoice, persist::error::PersistError, CustomMessage, MaxChannelAmount,
NodeCredentials, Payment, PaymentResponse, Peer, PrepareRedeemOnchainFundsRequest,
PrepareRedeemOnchainFundsResponse, RouteHint, RouteHintHop, SyncResponse, TlvEntry,
invoice::InvoiceError,
lightning_invoice::RawBolt11Invoice,
persist::error::PersistError,
CustomMessage, MaxChannelAmount, NodeCredentials, Payment, PaymentResponse, Peer,
PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, RouteHint, RouteHintHop,
SyncResponse, TlvEntry,
};

pub type NodeResult<T, E = NodeError> = Result<T, E>;
Expand Down Expand Up @@ -65,18 +68,15 @@ pub struct CreateInvoiceRequest {

pub struct FetchBolt11Result {
pub bolt11: String,
pub payer_amount_msat: Option<u64>
pub payer_amount_msat: Option<u64>,
}

/// Trait covering functions affecting the LN node
#[tonic::async_trait]
pub trait NodeAPI: Send + Sync {
fn node_credentials(&self) -> NodeResult<Option<NodeCredentials>>;
async fn configure_node(&self, close_to_address: Option<String>) -> NodeResult<()>;
async fn create_invoice(
&self,
request: CreateInvoiceRequest,
) -> NodeResult<String>;
async fn create_invoice(&self, request: CreateInvoiceRequest) -> NodeResult<String>;
/// Fetches an existing BOLT11 invoice from the node
async fn fetch_bolt11(&self, payment_hash: Vec<u8>) -> NodeResult<Option<FetchBolt11Result>>;
async fn pull_changed(
Expand Down Expand Up @@ -128,6 +128,7 @@ pub trait NodeAPI: Send + Sync {
) -> NodeResult<Streaming<gl_client::signer::model::greenlight::LogEntry>>;
async fn static_backup(&self) -> NodeResult<Vec<String>>;
async fn execute_command(&self, command: String) -> NodeResult<String>;
async fn generate_diagnostic_data(&self) -> NodeResult<String>;
async fn sign_message(&self, message: &str) -> NodeResult<String>;
async fn check_message(&self, message: &str, pubkey: &str, signature: &str)
-> NodeResult<bool>;
Expand Down
3 changes: 3 additions & 0 deletions libs/sdk-core/src/persist/settings.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use serde::Serialize;

use super::{db::SqliteStorage, error::PersistResult};

#[allow(dead_code)]
#[derive(Serialize)]
pub struct SettingItem {
key: String,
value: String,
Expand Down
52 changes: 33 additions & 19 deletions libs/sdk-core/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use chrono::{SecondsFormat, Utc};
use gl_client::signer::model::greenlight::amount::Unit;
use gl_client::signer::model::greenlight::Amount;
use gl_client::signer::model::greenlight::PayStatus;
use rand::distributions::uniform::{SampleRange, SampleUniform};
use rand::distributions::{Alphanumeric, DistString, Standard};
use rand::rngs::OsRng;
use rand::{random, Rng};
use rand::distributions::uniform::{SampleRange, SampleUniform};
use tokio::sync::{mpsc, Mutex};
use tokio::time::sleep;
use tokio_stream::Stream;
Expand All @@ -34,14 +34,22 @@ use crate::invoice::{InvoiceError, InvoiceResult};
use crate::lightning::ln::PaymentSecret;
use crate::lightning_invoice::{Currency, InvoiceBuilder, RawBolt11Invoice};
use crate::lsp::LspInformation;
use crate::models::{FiatAPI, LspAPI, NodeState, Payment, ReverseSwapServiceAPI, Swap, SwapperAPI, SyncResponse, TlvEntry};
use crate::models::{
FiatAPI, LspAPI, NodeState, Payment, ReverseSwapServiceAPI, Swap, SwapperAPI, SyncResponse,
TlvEntry,
};
use crate::moonpay::MoonPayApi;
use crate::node_api::{CreateInvoiceRequest, FetchBolt11Result, NodeAPI, NodeError, NodeResult};
use crate::swap_in::error::SwapResult;
use crate::swap_in::swap::create_submarine_swap_script;
use crate::{parse_invoice, Config, CustomMessage, LNInvoice, MaxChannelAmount, NodeCredentials, OpeningFeeParams, OpeningFeeParamsMenu, PaymentResponse, Peer, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, ReceivePaymentRequest, RouteHint, RouteHintHop, SwapInfo, ReverseSwapPairInfo};
use crate::swap_out::boltzswap::{BoltzApiCreateReverseSwapResponse, BoltzApiReverseSwapStatus};
use crate::swap_out::error::{ReverseSwapError, ReverseSwapResult};
use crate::{
parse_invoice, Config, CustomMessage, LNInvoice, MaxChannelAmount, NodeCredentials,
OpeningFeeParams, OpeningFeeParamsMenu, PaymentResponse, Peer,
PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, ReceivePaymentRequest,
ReverseSwapPairInfo, RouteHint, RouteHintHop, SwapInfo,
};

pub const MOCK_REVERSE_SWAP_MIN: u64 = 50_000;
pub const MOCK_REVERSE_SWAP_MAX: u64 = 1_000_000;
Expand Down Expand Up @@ -152,13 +160,13 @@ pub struct MockReverseSwapperAPI {}
impl ReverseSwapServiceAPI for MockReverseSwapperAPI {
async fn fetch_reverse_swap_fees(&self) -> ReverseSwapResult<ReverseSwapPairInfo> {
Ok(ReverseSwapPairInfo {
min: MOCK_REVERSE_SWAP_MIN,
max: MOCK_REVERSE_SWAP_MAX,
fees_hash: rand_string(5),
fees_percentage: 0.5,
fees_lockup: 3_000 + rand_int_in_range(1..1_000),
fees_claim: 3_000 + rand_int_in_range(1..1_000),
total_fees: None,
min: MOCK_REVERSE_SWAP_MIN,
max: MOCK_REVERSE_SWAP_MAX,
fees_hash: rand_string(5),
fees_percentage: 0.5,
fees_lockup: 3_000 + rand_int_in_range(1..1_000),
fees_claim: 3_000 + rand_int_in_range(1..1_000),
total_fees: None,
})
}

Expand All @@ -168,7 +176,7 @@ impl ReverseSwapServiceAPI for MockReverseSwapperAPI {
_preimage_hash_hex: String,
_claim_pubkey: String,
_pair_hash: String,
_routing_node: String
_routing_node: String,
) -> ReverseSwapResult<BoltzApiCreateReverseSwapResponse> {
Err(ReverseSwapError::Generic(anyhow!("Not implemented")))
}
Expand Down Expand Up @@ -331,11 +339,13 @@ impl NodeAPI for MockNodeAPI {
Ok(())
}

async fn create_invoice(
&self,
request: CreateInvoiceRequest,
) -> NodeResult<String> {
let invoice = create_invoice(request.description, request.amount_msat, vec![], request.preimage);
async fn create_invoice(&self, request: CreateInvoiceRequest) -> NodeResult<String> {
let invoice = create_invoice(
request.description,
request.amount_msat,
vec![],
request.preimage,
);
Ok(invoice.bolt11)
}

Expand Down Expand Up @@ -446,6 +456,10 @@ impl NodeAPI for MockNodeAPI {
Err(NodeError::Generic(anyhow!("Not implemented")))
}

async fn generate_diagnostic_data(&self) -> NodeResult<String> {
Ok("".to_string())
}

async fn max_sendable_amount(
&self,
_payee_node_id: Option<Vec<u8>>,
Expand Down Expand Up @@ -727,9 +741,9 @@ pub fn rand_vec_u8(len: usize) -> Vec<u8> {
}

pub fn rand_int_in_range<T, R>(range: R) -> T
where
T: SampleUniform,
R: SampleRange<T>
where
T: SampleUniform,
R: SampleRange<T>,
{
rand::thread_rng().gen_range(range)
}
Expand Down
3 changes: 3 additions & 0 deletions libs/sdk-flutter/ios/Classes/bridge_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ void wire_recommended_fees(int64_t port_);

void wire_execute_command(int64_t port_, struct wire_uint_8_list *command);

void wire_generate_diagnostic_data(int64_t port_);

bool *new_box_autoadd_bool_0(bool value);

struct wire_BuyBitcoinRequest *new_box_autoadd_buy_bitcoin_request_0(void);
Expand Down Expand Up @@ -549,6 +551,7 @@ static int64_t dummy_method_to_enforce_bundling(void) {
dummy_var ^= ((int64_t) (void*) wire_in_progress_onchain_payments);
dummy_var ^= ((int64_t) (void*) wire_recommended_fees);
dummy_var ^= ((int64_t) (void*) wire_execute_command);
dummy_var ^= ((int64_t) (void*) wire_generate_diagnostic_data);
dummy_var ^= ((int64_t) (void*) new_box_autoadd_bool_0);
dummy_var ^= ((int64_t) (void*) new_box_autoadd_buy_bitcoin_request_0);
dummy_var ^= ((int64_t) (void*) new_box_autoadd_check_message_request_0);
Expand Down
6 changes: 6 additions & 0 deletions libs/sdk-flutter/lib/breez_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,12 @@ class BreezSDK {
return await _lnToolkit.executeCommand(command: command);
}

/// Generate diagnostic data.
/// Mainly used to debugging.
Future<String> generateDiagnosticData() async {
return await _lnToolkit.generateDiagnosticData();
}

/* Helper Methods */

/// Validate if given address is a valid BTC address
Expand Down
Loading

0 comments on commit 759c22d

Please sign in to comment.