From 38df6fca526f5ff0c88c455b2d631bb516a565c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 10 Oct 2024 16:56:36 +0200 Subject: [PATCH] add /checkindexerurl API --- README.md | 1 + openapi.yaml | 34 ++++++++++++++++++++++++++++++++++ src/error.rs | 4 ++++ src/ldk.rs | 3 +-- src/main.rs | 17 +++++++++-------- src/rgb.rs | 18 ++++++++---------- src/routes.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 99 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d35e701..cd4ced8 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ The node currently exposes the following APIs: - `/backup` (POST) - `/btcbalance` (POST) - `/changepassword` (POST) +- `/checkindexerurl` (POST) - `/closechannel` (POST) - `/connectpeer` (POST) - `/createutxos` (POST) diff --git a/openapi.yaml b/openapi.yaml index bd30832..6001ed5 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -115,6 +115,24 @@ paths: application/json: schema: $ref: '#/components/schemas/EmptyResponse' + /checkindexerurl: + post: + tags: + - Other + summary: Check an indexer URL + description: Check the given indexer URL is valid + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CheckIndexerUrlRequest' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/CheckIndexerUrlResponse' /closechannel: post: tags: @@ -1099,6 +1117,17 @@ components: asset_remote_amount: type: integer example: 0 + CheckIndexerUrlRequest: + type: object + properties: + indexer_url: + type: string + example: 127.0.0.1:50001 + CheckIndexerUrlResponse: + type: object + properties: + indexer_protocol: + $ref: '#/components/schemas/IndexerProtocol' CloseChannelRequest: type: object properties: @@ -1250,6 +1279,11 @@ components: - Pending - Succeeded - Failed + IndexerProtocol: + type: string + enum: + - Electrum + - Esplora InitRequest: type: object properties: diff --git a/src/error.rs b/src/error.rs index e797e78..8a632e2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -73,6 +73,9 @@ pub enum APIError { #[error("For an RGB operation both asset_id and asset_amount must be set")] IncompleteRGBInfo, + #[error("Indexer error: {0}")] + Indexer(String), + #[error("Not enough assets")] InsufficientAssets, @@ -272,6 +275,7 @@ impl IntoResponse for APIError { | APIError::CannotOpenChannel(_) | APIError::ChangingState | APIError::FailedBitcoindConnection(_) + | APIError::Indexer(_) | APIError::InsufficientAssets | APIError::InsufficientFunds(_) | APIError::InvalidIndexer(_) diff --git a/src/ldk.rs b/src/ldk.rs index 0204a5f..aebae32 100644 --- a/src/ldk.rs +++ b/src/ldk.rs @@ -1413,8 +1413,7 @@ pub(crate) async fn start_ldk( // RGB setup let indexer_url = if let Some(indexer_url) = &unlock_request.indexer_url { - check_indexer_url(indexer_url, bitcoin_network) - .map_err(|e| APIError::InvalidIndexer(e.to_string()))?; + check_indexer_url(indexer_url, bitcoin_network)?; indexer_url } else { match bitcoin_network { diff --git a/src/main.rs b/src/main.rs index ddc816d..896d919 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,14 +29,14 @@ use crate::args::LdkUserInfo; use crate::error::AppError; use crate::ldk::stop_ldk; use crate::routes::{ - address, asset_balance, backup, btc_balance, change_password, close_channel, connect_peer, - create_utxos, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, estimate_fee, - get_asset_media, get_channel_id, init, invoice_status, issue_asset_cfa, issue_asset_nia, - issue_asset_uda, keysend, list_assets, list_channels, list_payments, list_peers, list_swaps, - list_transactions, list_transfers, list_unspents, ln_invoice, lock, maker_execute, maker_init, - network_info, node_info, open_channel, post_asset_media, refresh_transfers, restore, - rgb_invoice, send_asset, send_btc, send_onion_message, send_payment, shutdown, sign_message, - sync, taker, unlock, + address, asset_balance, backup, btc_balance, change_password, check_indexer_url, close_channel, + connect_peer, create_utxos, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, + estimate_fee, get_asset_media, get_channel_id, init, invoice_status, issue_asset_cfa, + issue_asset_nia, issue_asset_uda, keysend, list_assets, list_channels, list_payments, + list_peers, list_swaps, list_transactions, list_transfers, list_unspents, ln_invoice, lock, + maker_execute, maker_init, network_info, node_info, open_channel, post_asset_media, + refresh_transfers, restore, rgb_invoice, send_asset, send_btc, send_onion_message, + send_payment, shutdown, sign_message, sync, taker, unlock, }; use crate::utils::{start_daemon, AppState, LOGS_DIR}; @@ -95,6 +95,7 @@ pub(crate) async fn app(args: LdkUserInfo) -> Result<(Router, Arc), Ap .route("/backup", post(backup)) .route("/btcbalance", post(btc_balance)) .route("/changepassword", post(change_password)) + .route("/checkindexerurl", post(check_indexer_url)) .route("/closechannel", post(close_channel)) .route("/connectpeer", post(connect_peer)) .route("/createutxos", post(create_utxos)) diff --git a/src/rgb.rs b/src/rgb.rs index ff25513..e724359 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -20,8 +20,8 @@ use rgb_lib::{ ReceiveData, Recipient, RefreshResult, SendResult, Transaction as RgbLibTransaction, Transfer, Unspent, WalletData, }, - AssetSchema, Contract, ContractId, Error as RgbLibError, RgbTransfer, UpdateRes, - Wallet as RgbLibWallet, + AssetSchema, BitcoinNetwork, Contract, ContractId, Error as RgbLibError, RgbTransfer, + UpdateRes, Wallet as RgbLibWallet, }; use std::collections::HashMap; use std::path::{Path, PathBuf}; @@ -279,6 +279,10 @@ impl RgbLibWalletWrapper { self.wallet.lock().unwrap() } + pub(crate) fn bitcoin_network(&self) -> BitcoinNetwork { + self.get_rgb_wallet().get_wallet_data().bitcoin_network + } + pub(crate) fn blind_receive( &self, asset_id: Option, @@ -593,14 +597,8 @@ impl ChangeDestinationSource for RgbLibWalletWrapper { impl WalletSource for RgbLibWalletWrapper { fn list_confirmed_utxos(&self) -> Result, ()> { let wallet = self.wallet.lock().unwrap(); - let network = Network::from_str( - &wallet - .get_wallet_data() - .bitcoin_network - .to_string() - .to_lowercase(), - ) - .unwrap(); + let network = + Network::from_str(&self.bitcoin_network().to_string().to_lowercase()).unwrap(); Ok(wallet.list_unspents_vanilla(self.online.clone(), 1, false).unwrap().iter().filter_map(|u| { let script = u.txout.script_pubkey.clone().into_boxed_script(); let address = Address::from_script(&script, network).unwrap(); diff --git a/src/routes.rs b/src/routes.rs index aef32fa..6017380 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -43,6 +43,10 @@ use rgb_lib::{ generate_keys, utils::recipient_id_from_script_buf, wallet::{ + rust_only::{ + check_indexer_url as rgb_lib_check_indexer_url, + IndexerProtocol as RgbLibIndexerProtocol, + }, AssetCFA as RgbLibAssetCFA, AssetIface as RgbLibAssetIface, AssetNIA as RgbLibAssetNIA, AssetUDA as RgbLibAssetUDA, Balance as RgbLibBalance, Invoice as RgbLibInvoice, Media as RgbLibMedia, Recipient, RecipientInfo, TokenLight as RgbLibTokenLight, @@ -347,6 +351,16 @@ pub(crate) struct Channel { pub(crate) asset_remote_amount: Option, } +#[derive(Debug, Deserialize, Serialize)] +pub(crate) struct CheckIndexerUrlRequest { + pub(crate) indexer_url: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub(crate) struct CheckIndexerUrlResponse { + pub(crate) indexer_protocol: IndexerProtocol, +} + #[derive(Deserialize, Serialize)] pub(crate) struct CloseChannelRequest { pub(crate) channel_id: String, @@ -453,6 +467,21 @@ impl_writeable_tlv_based_enum!(HTLCStatus, (2, Failed) => {}; ); +#[derive(Debug, Deserialize, Serialize)] +pub(crate) enum IndexerProtocol { + Electrum, + Esplora, +} + +impl From for IndexerProtocol { + fn from(x: RgbLibIndexerProtocol) -> Self { + match x { + RgbLibIndexerProtocol::Electrum => Self::Electrum, + RgbLibIndexerProtocol::Esplora => Self::Esplora, + } + } +} + #[derive(Deserialize, Serialize)] pub(crate) struct InitRequest { pub(crate) password: String, @@ -1018,6 +1047,7 @@ impl From for APIError { RgbLibError::AllocationsAlreadyAvailable => APIError::AllocationsAlreadyAvailable, RgbLibError::AssetNotFound { .. } => APIError::UnknownContractId, RgbLibError::FailedIssuance { details } => APIError::FailedIssuingAsset(details), + RgbLibError::Indexer { details } => APIError::Indexer(details), RgbLibError::InsufficientAllocationSlots => APIError::NoAvailableUtxos, RgbLibError::InsufficientBitcoins { needed, available } => { APIError::InsufficientFunds(needed - available) @@ -1025,7 +1055,9 @@ impl From for APIError { RgbLibError::InsufficientSpendableAssets { .. } => APIError::InsufficientAssets, RgbLibError::InsufficientTotalAssets { .. } => APIError::InsufficientAssets, RgbLibError::InvalidAssetID { asset_id } => APIError::InvalidAssetID(asset_id), + RgbLibError::InvalidElectrum { details } => APIError::InvalidIndexer(details), RgbLibError::InvalidFeeRate { details } => APIError::InvalidFeeRate(details), + RgbLibError::InvalidIndexer { details } => APIError::InvalidIndexer(details), RgbLibError::InvalidName { details } => APIError::InvalidName(details), RgbLibError::InvalidPrecision { details } => APIError::InvalidPrecision(details), RgbLibError::InvalidRecipientID => APIError::InvalidRecipientID, @@ -1160,6 +1192,16 @@ pub(crate) async fn change_password( .await } +pub(crate) async fn check_indexer_url( + State(state): State>, + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + let indexer_protocol = + rgb_lib_check_indexer_url(&payload.indexer_url, state.static_state.network)?.into(); + + Ok(Json(CheckIndexerUrlResponse { indexer_protocol })) +} + pub(crate) async fn close_channel( State(state): State>, WithRejection(Json(payload), _): WithRejection, APIError>,