From 3b8ff6b7e9826cef5457369a1c322ad529bc9ba1 Mon Sep 17 00:00:00 2001 From: ka Date: Wed, 4 Jun 2025 23:24:31 +0800 Subject: [PATCH 1/6] Add /encodeassetid and /decodeassetid APIs --- openapi.yaml | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 4 ++- src/routes.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index c152fdc..6cf6245 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -223,6 +223,29 @@ paths: application/json: schema: $ref: '#/components/schemas/EmptyResponse' + /decodeassetid: + post: + summary: Decode RGB asset ID to hexadecimal format + description: Convert RGB format asset ID (rgb:xxx) to hexadecimal format + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DecodeAssetIdRequest' + responses: + '200': + description: Asset ID encoding result + content: + application/json: + schema: + $ref: '#/components/schemas/DecodeAssetIdResponse' + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Locked' + '500': + $ref: '#/components/responses/InternalServerError' /decodelninvoice: post: tags: @@ -277,6 +300,29 @@ paths: application/json: schema: $ref: '#/components/schemas/EmptyResponse' + /encodeassetid: + post: + summary: Encode hexadecimal asset ID to RGB format + description: Convert hexadecimal format asset ID to RGB format (rgb:xxx) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EncodeAssetIdRequest' + responses: + '200': + description: Asset ID decoding result + content: + application/json: + schema: + $ref: '#/components/schemas/EncodeAssetIdResponse' + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Locked' + '500': + $ref: '#/components/responses/InternalServerError' /estimatefee: post: tags: @@ -1288,6 +1334,21 @@ components: skip_sync: type: boolean example: false + DecodeAssetIdRequest: + type: object + properties: + asset_id: + type: string + example: rgb:2dkSTbr-jFhznbPmo-TQafzswCN-av4gTsJjX-ttx6CNou5-M98k8Zd + DecodeAssetIdResponse: + type: object + properties: + hex_format: + type: string + example: aa1c3d3ef10424cf64e45ea93516c14766be91031c39715783a4f78bd7e64a8a + asset_id: + type: string + example: rgb:2dkSTbr-jFhznbPmo-TQafzswCN-av4gTsJjX-ttx6CNou5-M98k8Zd DecodeLNInvoiceRequest: type: object properties: @@ -1359,6 +1420,21 @@ components: peer_pubkey: type: string example: 03b79a4bc1ec365524b4fab9a39eb133753646babb5a1da5c4bc94c53110b7795d + EncodeAssetIdRequest: + type: object + properties: + hex_format: + type: string + example: aa1c3d3ef10424cf64e45ea93516c14766be91031c39715783a4f78bd7e64a8a + EncodeAssetIdResponse: + type: object + properties: + hex_format: + type: string + example: aa1c3d3ef10424cf64e45ea93516c14766be91031c39715783a4f78bd7e64a8a + asset_id: + type: string + example: rgb:2dkSTbr-jFhznbPmo-TQafzswCN-av4gTsJjX-ttx6CNou5-M98k8Zd EmbeddedMedia: type: object properties: diff --git a/src/main.rs b/src/main.rs index ff0e7ec..8e7b912 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ use crate::ldk::stop_ldk; use crate::routes::{ address, asset_balance, asset_metadata, backup, btc_balance, change_password, check_indexer_url, check_proxy_endpoint, close_channel, connect_peer, create_utxos, - decode_ln_invoice, decode_rgb_invoice, disconnect_peer, estimate_fee, fail_transfers, + decode_asset_id, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, encode_asset_id, estimate_fee, fail_transfers, get_asset_media, get_channel_id, get_payment, get_swap, 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, @@ -112,9 +112,11 @@ pub(crate) async fn app(args: LdkUserInfo) -> Result<(Router, Arc), Ap .route("/closechannel", post(close_channel)) .route("/connectpeer", post(connect_peer)) .route("/createutxos", post(create_utxos)) + .route("/decodeassetid", post(decode_asset_id)) .route("/decodelninvoice", post(decode_ln_invoice)) .route("/decodergbinvoice", post(decode_rgb_invoice)) .route("/disconnectpeer", post(disconnect_peer)) + .route("/encodeassetid", post(encode_asset_id)) .route("/estimatefee", post(estimate_fee)) .route("/failtransfers", post(fail_transfers)) .route("/getassetmedia", post(get_asset_media)) diff --git a/src/routes.rs b/src/routes.rs index e00c46e..8f195c3 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -3598,3 +3598,71 @@ pub(crate) async fn unlock( }) .await } + + + +#[derive(Deserialize, Serialize)] +pub(crate) struct DecodeAssetIdRequest { + pub(crate) asset_id: String, +} + +#[derive(Deserialize, Serialize)] +pub(crate) struct DecodeAssetIdResponse { + pub(crate) hex_format: String, + pub(crate) asset_id: String, +} + +#[derive(Deserialize, Serialize)] +pub(crate) struct EncodeAssetIdRequest { + pub(crate) hex_format: String, +} + +#[derive(Deserialize, Serialize)] +pub(crate) struct EncodeAssetIdResponse { + pub(crate) hex_format: String, + pub(crate) asset_id: String, +} + +pub(crate) async fn decode_asset_id( + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + + let contract_id = ContractId::from_str(&payload.asset_id) + .map_err(|_| APIError::InvalidAssetID(payload.asset_id.clone()))?; + + let bytes: &[u8] = &contract_id[..]; + let hex_format = bytes.iter() + .map(|b| format!("{:02x}", b)) + .collect::(); + + Ok(Json(DecodeAssetIdResponse { hex_format, asset_id: payload.asset_id })) +} + +pub(crate) async fn encode_asset_id( + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + if payload.hex_format.len() != 64 { + return Err(APIError::InvalidAssetID(format!( + "Hex format asset ID must be 64 characters, actual length: {}", + payload.hex_format.len() + ))); + } + + let hex_bytes = hex_str_to_vec(&payload.hex_format) + .ok_or_else(|| APIError::InvalidAssetID(format!( + "Invalid hex string: {}", + payload.hex_format + )))?; + + if hex_bytes.len() != 32 { + return Err(APIError::InvalidAssetID(format!( + "Contract ID must be 32 bytes, actual: {} bytes", + hex_bytes.len() + ))); + } + + let contract_id = ContractId::from(<[u8; 32]>::try_from(hex_bytes).unwrap()); + let asset_id = contract_id.to_string(); + + Ok(Json(EncodeAssetIdResponse { hex_format: payload.hex_format, asset_id })) +} From b00e4228ac76249dc01d3968950c58d2496fcabf Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 13 Jun 2025 16:55:11 +0800 Subject: [PATCH 2/6] add test function --- src/routes.rs | 87 +++++++++++++++--------------- src/test/encode_decode_asset_id.rs | 44 +++++++++++++++ src/test/mod.rs | 57 +++++++++++++------- 3 files changed, 126 insertions(+), 62 deletions(-) create mode 100644 src/test/encode_decode_asset_id.rs diff --git a/src/routes.rs b/src/routes.rs index 8f195c3..7ce68ee 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1432,6 +1432,21 @@ pub(crate) async fn create_utxos( .await } +pub(crate) async fn decode_asset_id( + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + + let contract_id = ContractId::from_str(&payload.asset_id) + .map_err(|_| APIError::InvalidAssetID(payload.asset_id.clone()))?; + + let bytes: &[u8] = &contract_id[..]; + let hex_format = bytes.iter() + .map(|b| format!("{:02x}", b)) + .collect::(); + + Ok(Json(DecodeAssetIdResponse { hex_format, asset_id: payload.asset_id })) +} + pub(crate) async fn decode_ln_invoice( State(state): State>, WithRejection(Json(payload), _): WithRejection, APIError>, @@ -1522,6 +1537,35 @@ pub(crate) async fn disconnect_peer( .await } +pub(crate) async fn encode_asset_id( + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + if payload.hex_format.len() != 64 { + return Err(APIError::InvalidAssetID(format!( + "Hex format asset ID must be 64 characters, actual length: {}", + payload.hex_format.len() + ))); + } + + let hex_bytes = hex_str_to_vec(&payload.hex_format) + .ok_or_else(|| APIError::InvalidAssetID(format!( + "Invalid hex string: {}", + payload.hex_format + )))?; + + if hex_bytes.len() != 32 { + return Err(APIError::InvalidAssetID(format!( + "Contract ID must be 32 bytes, actual: {} bytes", + hex_bytes.len() + ))); + } + + let contract_id = ContractId::from(<[u8; 32]>::try_from(hex_bytes).unwrap()); + let asset_id = contract_id.to_string(); + + Ok(Json(EncodeAssetIdResponse { hex_format: payload.hex_format, asset_id })) +} + pub(crate) async fn estimate_fee( State(state): State>, WithRejection(Json(payload), _): WithRejection, APIError>, @@ -3623,46 +3667,3 @@ pub(crate) struct EncodeAssetIdResponse { pub(crate) asset_id: String, } -pub(crate) async fn decode_asset_id( - WithRejection(Json(payload), _): WithRejection, APIError>, -) -> Result, APIError> { - - let contract_id = ContractId::from_str(&payload.asset_id) - .map_err(|_| APIError::InvalidAssetID(payload.asset_id.clone()))?; - - let bytes: &[u8] = &contract_id[..]; - let hex_format = bytes.iter() - .map(|b| format!("{:02x}", b)) - .collect::(); - - Ok(Json(DecodeAssetIdResponse { hex_format, asset_id: payload.asset_id })) -} - -pub(crate) async fn encode_asset_id( - WithRejection(Json(payload), _): WithRejection, APIError>, -) -> Result, APIError> { - if payload.hex_format.len() != 64 { - return Err(APIError::InvalidAssetID(format!( - "Hex format asset ID must be 64 characters, actual length: {}", - payload.hex_format.len() - ))); - } - - let hex_bytes = hex_str_to_vec(&payload.hex_format) - .ok_or_else(|| APIError::InvalidAssetID(format!( - "Invalid hex string: {}", - payload.hex_format - )))?; - - if hex_bytes.len() != 32 { - return Err(APIError::InvalidAssetID(format!( - "Contract ID must be 32 bytes, actual: {} bytes", - hex_bytes.len() - ))); - } - - let contract_id = ContractId::from(<[u8; 32]>::try_from(hex_bytes).unwrap()); - let asset_id = contract_id.to_string(); - - Ok(Json(EncodeAssetIdResponse { hex_format: payload.hex_format, asset_id })) -} diff --git a/src/test/encode_decode_asset_id.rs b/src/test/encode_decode_asset_id.rs new file mode 100644 index 0000000..bbe2450 --- /dev/null +++ b/src/test/encode_decode_asset_id.rs @@ -0,0 +1,44 @@ +use super::*; + +const TEST_DIR_BASE: &str = "tmp/asset_id/"; + +#[serial_test::serial] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[traced_test] +async fn asset_id() { + initialize(); + + let amt = 5000; + let file_path = "README.md"; + + let test_dir_node1 = format!("{TEST_DIR_BASE}node1"); + let (node1_addr, _) = start_node(&test_dir_node1, NODE1_PEER_PORT, false).await; + + fund_and_create_utxos(node1_addr, None).await; + + // check /createutxos size parameter + let unspents_1 = list_unspents(node1_addr).await; + create_utxos(node1_addr, false, Some(1), Some(amt)).await; + let unspents_2 = list_unspents(node1_addr).await; + assert_eq!(unspents_1.len(), unspents_2.len() - 1); + assert!(!unspents_1.iter().any(|u| u.utxo.btc_amount == amt as u64)); + assert!(unspents_2.iter().any(|u| u.utxo.btc_amount == amt as u64)); + + // issue assets + let asset_cfa = issue_asset_cfa(node1_addr, Some(file_path)).await; + let asset_nia = issue_asset_nia(node1_addr).await; + let asset_uda = issue_asset_uda(node1_addr, Some(file_path)).await; + + // check + let cfa_decoded_result = decode_asset_id(node1_addr, asset_cfa.asset_id.clone()).await; + let nia_decoded_result = decode_asset_id(node1_addr, asset_nia.asset_id.clone()).await; + let uda_decoded_result = decode_asset_id(node1_addr, asset_uda.asset_id.clone()).await; + + let cfa_encoded_result = encode_asset_id(node1_addr, cfa_decoded_result.hex_format.clone()).await; + let nia_encoded_result = encode_asset_id(node1_addr, nia_decoded_result.hex_format.clone()).await; + let uda_encoded_result = encode_asset_id(node1_addr, uda_decoded_result.hex_format.clone()).await; + + assert_eq!(cfa_encoded_result.asset_id, asset_cfa.asset_id); + assert_eq!(nia_encoded_result.asset_id, asset_nia.asset_id); + assert_eq!(uda_encoded_result.asset_id, asset_uda.asset_id); +} diff --git a/src/test/mod.rs b/src/test/mod.rs index fb72334..03edc0a 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -18,25 +18,7 @@ use tracing_test::traced_test; use crate::error::APIErrorResponse; use crate::ldk::FEE_RATE; use crate::routes::{ - AddressResponse, AssetBalanceRequest, AssetBalanceResponse, AssetCFA, AssetNIA, AssetUDA, - BackupRequest, BtcBalanceRequest, BtcBalanceResponse, ChangePasswordRequest, Channel, - CloseChannelRequest, ConnectPeerRequest, CreateUtxosRequest, DecodeLNInvoiceRequest, - DecodeLNInvoiceResponse, DecodeRGBInvoiceRequest, DecodeRGBInvoiceResponse, - DisconnectPeerRequest, EmptyResponse, FailTransfersRequest, FailTransfersResponse, - GetAssetMediaRequest, GetAssetMediaResponse, GetChannelIdRequest, GetChannelIdResponse, - GetPaymentRequest, GetPaymentResponse, GetSwapRequest, GetSwapResponse, HTLCStatus, - InitRequest, InitResponse, InvoiceStatus, InvoiceStatusRequest, InvoiceStatusResponse, - IssueAssetCFARequest, IssueAssetCFAResponse, IssueAssetNIARequest, IssueAssetNIAResponse, - IssueAssetUDARequest, IssueAssetUDAResponse, KeysendRequest, KeysendResponse, LNInvoiceRequest, - LNInvoiceResponse, ListAssetsRequest, ListAssetsResponse, ListChannelsResponse, - ListPaymentsResponse, ListPeersResponse, ListSwapsResponse, ListTransactionsRequest, - ListTransactionsResponse, ListTransfersRequest, ListTransfersResponse, ListUnspentsRequest, - ListUnspentsResponse, MakerExecuteRequest, MakerInitRequest, MakerInitResponse, - NetworkInfoResponse, NodeInfoResponse, OpenChannelRequest, OpenChannelResponse, Payment, Peer, - PostAssetMediaResponse, RefreshRequest, RestoreRequest, RgbInvoiceRequest, RgbInvoiceResponse, - SendAssetRequest, SendAssetResponse, SendBtcRequest, SendBtcResponse, SendPaymentRequest, - SendPaymentResponse, Swap, SwapStatus, TakerRequest, Transaction, Transfer, UnlockRequest, - Unspent, + AddressResponse, AssetBalanceRequest, AssetBalanceResponse, AssetCFA, AssetNIA, AssetUDA, BackupRequest, BtcBalanceRequest, BtcBalanceResponse, ChangePasswordRequest, Channel, CloseChannelRequest, ConnectPeerRequest, CreateUtxosRequest, DecodeAssetIdRequest, DecodeAssetIdResponse, DecodeLNInvoiceRequest, DecodeLNInvoiceResponse, DecodeRGBInvoiceRequest, DecodeRGBInvoiceResponse, DisconnectPeerRequest, EmptyResponse, EncodeAssetIdRequest, EncodeAssetIdResponse, FailTransfersRequest, FailTransfersResponse, GetAssetMediaRequest, GetAssetMediaResponse, GetChannelIdRequest, GetChannelIdResponse, GetPaymentRequest, GetPaymentResponse, GetSwapRequest, GetSwapResponse, HTLCStatus, InitRequest, InitResponse, InvoiceStatus, InvoiceStatusRequest, InvoiceStatusResponse, IssueAssetCFARequest, IssueAssetCFAResponse, IssueAssetNIARequest, IssueAssetNIAResponse, IssueAssetUDARequest, IssueAssetUDAResponse, KeysendRequest, KeysendResponse, LNInvoiceRequest, LNInvoiceResponse, ListAssetsRequest, ListAssetsResponse, ListChannelsResponse, ListPaymentsResponse, ListPeersResponse, ListSwapsResponse, ListTransactionsRequest, ListTransactionsResponse, ListTransfersRequest, ListTransfersResponse, ListUnspentsRequest, ListUnspentsResponse, MakerExecuteRequest, MakerInitRequest, MakerInitResponse, NetworkInfoResponse, NodeInfoResponse, OpenChannelRequest, OpenChannelResponse, Payment, Peer, PostAssetMediaResponse, RefreshRequest, RestoreRequest, RgbInvoiceRequest, RgbInvoiceResponse, SendAssetRequest, SendAssetResponse, SendBtcRequest, SendBtcResponse, SendPaymentRequest, SendPaymentResponse, Swap, SwapStatus, TakerRequest, Transaction, Transfer, UnlockRequest, Unspent }; use crate::utils::{hex_str_to_vec, ELECTRUM_URL_REGTEST, PROXY_ENDPOINT_LOCAL}; @@ -394,6 +376,24 @@ async fn create_utxos(node_address: SocketAddr, up_to: bool, num: Option, si .unwrap(); } +async fn decode_asset_id(node_address: SocketAddr, asset_id: String) -> DecodeAssetIdResponse { + println!("decoding asset ID {asset_id} for node {node_address}"); + let payload = DecodeAssetIdRequest { + asset_id, + }; + let res = reqwest::Client::new() + .post(format!("http://{}/decodeassetid", node_address)) + .json(&payload) + .send() + .await + .unwrap(); + _check_response_is_ok(res) + .await + .json::() + .await + .unwrap() +} + async fn decode_ln_invoice(node_address: SocketAddr, invoice: &str) -> DecodeLNInvoiceResponse { println!("decoding LN invoice {invoice} for node {node_address}"); let payload = DecodeLNInvoiceRequest { @@ -448,6 +448,24 @@ async fn disconnect_peer(node_address: SocketAddr, peer_pubkey: &str) { .unwrap(); } +async fn encode_asset_id(node_address: SocketAddr, asset_id: String) -> EncodeAssetIdResponse { + println!("encoding asset ID {asset_id} for node {node_address}"); + let payload = EncodeAssetIdRequest { + hex_format: asset_id, + }; + let res = reqwest::Client::new() + .post(format!("http://{}/encodeassetid", node_address)) + .json(&payload) + .send() + .await + .unwrap(); + _check_response_is_ok(res) + .await + .json::() + .await + .unwrap() +} + async fn fail_transfers(node_address: SocketAddr, batch_transfer_idx: Option) -> bool { println!( "failing transfers, batch_transfer_idx {batch_transfer_idx:?} from node {node_address}" @@ -1668,6 +1686,7 @@ mod close_force_nobtc_acceptor; mod close_force_other_side; mod close_force_standard; mod concurrent_btc_payments; +mod encode_decode_asset_id; mod fail_transfers; mod getchannelid; mod htlc_amount_checks; From 5323e546b512959947c3f89811d41b137a260fcd Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 13 Jun 2025 17:51:25 +0800 Subject: [PATCH 3/6] fix format --- src/test/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/mod.rs b/src/test/mod.rs index 03edc0a..ff40541 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -18,7 +18,15 @@ use tracing_test::traced_test; use crate::error::APIErrorResponse; use crate::ldk::FEE_RATE; use crate::routes::{ - AddressResponse, AssetBalanceRequest, AssetBalanceResponse, AssetCFA, AssetNIA, AssetUDA, BackupRequest, BtcBalanceRequest, BtcBalanceResponse, ChangePasswordRequest, Channel, CloseChannelRequest, ConnectPeerRequest, CreateUtxosRequest, DecodeAssetIdRequest, DecodeAssetIdResponse, DecodeLNInvoiceRequest, DecodeLNInvoiceResponse, DecodeRGBInvoiceRequest, DecodeRGBInvoiceResponse, DisconnectPeerRequest, EmptyResponse, EncodeAssetIdRequest, EncodeAssetIdResponse, FailTransfersRequest, FailTransfersResponse, GetAssetMediaRequest, GetAssetMediaResponse, GetChannelIdRequest, GetChannelIdResponse, GetPaymentRequest, GetPaymentResponse, GetSwapRequest, GetSwapResponse, HTLCStatus, InitRequest, InitResponse, InvoiceStatus, InvoiceStatusRequest, InvoiceStatusResponse, IssueAssetCFARequest, IssueAssetCFAResponse, IssueAssetNIARequest, IssueAssetNIAResponse, IssueAssetUDARequest, IssueAssetUDAResponse, KeysendRequest, KeysendResponse, LNInvoiceRequest, LNInvoiceResponse, ListAssetsRequest, ListAssetsResponse, ListChannelsResponse, ListPaymentsResponse, ListPeersResponse, ListSwapsResponse, ListTransactionsRequest, ListTransactionsResponse, ListTransfersRequest, ListTransfersResponse, ListUnspentsRequest, ListUnspentsResponse, MakerExecuteRequest, MakerInitRequest, MakerInitResponse, NetworkInfoResponse, NodeInfoResponse, OpenChannelRequest, OpenChannelResponse, Payment, Peer, PostAssetMediaResponse, RefreshRequest, RestoreRequest, RgbInvoiceRequest, RgbInvoiceResponse, SendAssetRequest, SendAssetResponse, SendBtcRequest, SendBtcResponse, SendPaymentRequest, SendPaymentResponse, Swap, SwapStatus, TakerRequest, Transaction, Transfer, UnlockRequest, Unspent + address, asset_balance, asset_metadata, backup, btc_balance, change_password, + check_indexer_url, check_proxy_endpoint, close_channel, connect_peer, create_utxos, + decode_asset_id, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, encode_asset_id, estimate_fee, fail_transfers, + get_asset_media, get_channel_id, get_payment, get_swap, 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::{hex_str_to_vec, ELECTRUM_URL_REGTEST, PROXY_ENDPOINT_LOCAL}; From f1e13c49e068ab7370bd6d255102b8deb26acb07 Mon Sep 17 00:00:00 2001 From: ka Date: Sat, 14 Jun 2025 22:30:28 +0800 Subject: [PATCH 4/6] add test for assetid(to|from)hexbytes APIs --- README.md | 2 + openapi.yaml | 138 +++++++++++++---------------- src/error.rs | 8 ++ src/main.rs | 8 +- src/routes.rs | 113 +++++++++-------------- src/test/asset_id_hex_bytes.rs | 33 +++++++ src/test/encode_decode_asset_id.rs | 44 --------- src/test/mod.rs | 76 ++++++++-------- 8 files changed, 190 insertions(+), 232 deletions(-) create mode 100644 src/test/asset_id_hex_bytes.rs delete mode 100644 src/test/encode_decode_asset_id.rs diff --git a/README.md b/README.md index e7f8832..62adf3b 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,8 @@ curl -X POST -H "Content-type: application/json" \ The node currently exposes the following APIs: - `/address` (POST) - `/assetbalance` (POST) +- `/assetidfromhexbytes` (POST) +- `/assetidtohexbytes` (POST) - `/assetmetadata` (POST) - `/backup` (POST) - `/btcbalance` (POST) diff --git a/openapi.yaml b/openapi.yaml index 6cf6245..cdc0758 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -61,6 +61,44 @@ paths: application/json: schema: $ref: '#/components/schemas/AssetBalanceResponse' + /assetidfromhexbytes: + post: + tags: + - RGB + summary: Convert hex-encoded bytes to RGB asset ID + description: Convert asset ID bytes in hexadecimal format to the corresponding baid64 string form + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AssetIdFromHexBytesRequest' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/AssetIdFromHexBytesResponse' + /assetidtohexbytes: + post: + tags: + - RGB + summary: Convert RGB asset ID to hex-encoded bytes + description: Convert RGB asset ID in baid64 string form to its bytes in hexadecimal format + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AssetIdToHexBytesRequest' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/AssetIdToHexBytesResponse' /assetmetadata: post: tags: @@ -223,29 +261,6 @@ paths: application/json: schema: $ref: '#/components/schemas/EmptyResponse' - /decodeassetid: - post: - summary: Decode RGB asset ID to hexadecimal format - description: Convert RGB format asset ID (rgb:xxx) to hexadecimal format - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/DecodeAssetIdRequest' - responses: - '200': - description: Asset ID encoding result - content: - application/json: - schema: - $ref: '#/components/schemas/DecodeAssetIdResponse' - '400': - $ref: '#/components/responses/BadRequest' - '403': - $ref: '#/components/responses/Locked' - '500': - $ref: '#/components/responses/InternalServerError' /decodelninvoice: post: tags: @@ -300,29 +315,6 @@ paths: application/json: schema: $ref: '#/components/schemas/EmptyResponse' - /encodeassetid: - post: - summary: Encode hexadecimal asset ID to RGB format - description: Convert hexadecimal format asset ID to RGB format (rgb:xxx) - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EncodeAssetIdRequest' - responses: - '200': - description: Asset ID decoding result - content: - application/json: - schema: - $ref: '#/components/schemas/EncodeAssetIdResponse' - '400': - $ref: '#/components/responses/BadRequest' - '403': - $ref: '#/components/responses/Locked' - '500': - $ref: '#/components/responses/InternalServerError' /estimatefee: post: tags: @@ -1032,6 +1024,30 @@ components: offchain_inbound: type: integer example: 0 + AssetIdFromHexBytesRequest: + type: object + properties: + hex_bytes: + type: string + example: 08991be186708d18b3dac93f3c044f8a8c2d558235717004602a8ec137ef459f + AssetIdFromHexBytesResponse: + type: object + properties: + asset_id: + type: string + example: rgb:CJkb4YZw-jRiz2sk-~PARPio-wtVYI1c-XAEYCqO-wTfvRZ8 + AssetIdToHexBytesRequest: + type: object + properties: + asset_id: + type: string + example: rgb:CJkb4YZw-jRiz2sk-~PARPio-wtVYI1c-XAEYCqO-wTfvRZ8 + AssetIdToHexBytesResponse: + type: object + properties: + hex_bytes: + type: string + example: 08991be186708d18b3dac93f3c044f8a8c2d558235717004602a8ec137ef459f AssetMetadataRequest: type: object properties: @@ -1334,21 +1350,6 @@ components: skip_sync: type: boolean example: false - DecodeAssetIdRequest: - type: object - properties: - asset_id: - type: string - example: rgb:2dkSTbr-jFhznbPmo-TQafzswCN-av4gTsJjX-ttx6CNou5-M98k8Zd - DecodeAssetIdResponse: - type: object - properties: - hex_format: - type: string - example: aa1c3d3ef10424cf64e45ea93516c14766be91031c39715783a4f78bd7e64a8a - asset_id: - type: string - example: rgb:2dkSTbr-jFhznbPmo-TQafzswCN-av4gTsJjX-ttx6CNou5-M98k8Zd DecodeLNInvoiceRequest: type: object properties: @@ -1420,21 +1421,6 @@ components: peer_pubkey: type: string example: 03b79a4bc1ec365524b4fab9a39eb133753646babb5a1da5c4bc94c53110b7795d - EncodeAssetIdRequest: - type: object - properties: - hex_format: - type: string - example: aa1c3d3ef10424cf64e45ea93516c14766be91031c39715783a4f78bd7e64a8a - EncodeAssetIdResponse: - type: object - properties: - hex_format: - type: string - example: aa1c3d3ef10424cf64e45ea93516c14766be91031c39715783a4f78bd7e64a8a - asset_id: - type: string - example: rgb:2dkSTbr-jFhznbPmo-TQafzswCN-av4gTsJjX-ttx6CNou5-M98k8Zd EmbeddedMedia: type: object properties: diff --git a/src/error.rs b/src/error.rs index 221ddb7..ccaf309 100644 --- a/src/error.rs +++ b/src/error.rs @@ -111,6 +111,9 @@ pub enum APIError { #[error("Invalid asset ID: {0}")] InvalidAssetID(String), + #[error("Invalid hex bytes")] + InvalidAssetIDBytes, + #[error("Invalid attachments: {0}")] InvalidAttachments(String), @@ -129,6 +132,9 @@ pub enum APIError { #[error("Invalid fee rate: {0}")] InvalidFeeRate(String), + #[error("Invalid hex string: {0}")] + InvalidHexString(String), + #[error("Invalid indexer: {0}")] InvalidIndexer(String), @@ -405,12 +411,14 @@ impl IntoResponse for APIError { | APIError::InvalidAnnounceAddresses(_) | APIError::InvalidAnnounceAlias(_) | APIError::InvalidAssetID(_) + | APIError::InvalidAssetIDBytes | APIError::InvalidAttachments(_) | APIError::InvalidBackupPath | APIError::InvalidChannelID | APIError::InvalidDetails(_) | APIError::InvalidEstimationBlocks | APIError::InvalidFeeRate(_) + | APIError::InvalidHexString(_) | APIError::InvalidInvoice(_) | APIError::InvalidMediaDigest | APIError::InvalidName(_) diff --git a/src/main.rs b/src/main.rs index 8e7b912..2b02f3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,9 +39,9 @@ use crate::args::LdkUserInfo; use crate::error::AppError; use crate::ldk::stop_ldk; use crate::routes::{ - address, asset_balance, asset_metadata, backup, btc_balance, change_password, + address, asset_balance, asset_id_from_hex_bytes, asset_id_to_hex_bytes, asset_metadata, backup, btc_balance, change_password, check_indexer_url, check_proxy_endpoint, close_channel, connect_peer, create_utxos, - decode_asset_id, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, encode_asset_id, estimate_fee, fail_transfers, + decode_ln_invoice, decode_rgb_invoice, disconnect_peer, estimate_fee, fail_transfers, get_asset_media, get_channel_id, get_payment, get_swap, 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, @@ -103,6 +103,8 @@ pub(crate) async fn app(args: LdkUserInfo) -> Result<(Router, Arc), Ap .layer(DefaultBodyLimit::disable()) .route("/address", post(address)) .route("/assetbalance", post(asset_balance)) + .route("/assetidfromhexbytes", post(asset_id_from_hex_bytes)) + .route("/assetidtohexbytes", post(asset_id_to_hex_bytes)) .route("/assetmetadata", post(asset_metadata)) .route("/backup", post(backup)) .route("/btcbalance", post(btc_balance)) @@ -112,11 +114,9 @@ pub(crate) async fn app(args: LdkUserInfo) -> Result<(Router, Arc), Ap .route("/closechannel", post(close_channel)) .route("/connectpeer", post(connect_peer)) .route("/createutxos", post(create_utxos)) - .route("/decodeassetid", post(decode_asset_id)) .route("/decodelninvoice", post(decode_ln_invoice)) .route("/decodergbinvoice", post(decode_rgb_invoice)) .route("/disconnectpeer", post(disconnect_peer)) - .route("/encodeassetid", post(encode_asset_id)) .route("/estimatefee", post(estimate_fee)) .route("/failtransfers", post(fail_transfers)) .route("/getassetmedia", post(get_asset_media)) diff --git a/src/routes.rs b/src/routes.rs index 7ce68ee..f06d677 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -141,6 +141,26 @@ impl From for AssetBalanceResponse { } } +#[derive(Deserialize, Serialize)] +pub(crate) struct AssetIdToHexBytesRequest { + pub(crate) asset_id: String, +} + +#[derive(Deserialize, Serialize)] +pub(crate) struct AssetIdToHexBytesResponse { + pub(crate) hex_bytes: String, +} + +#[derive(Deserialize, Serialize)] +pub(crate) struct AssetIdFromHexBytesRequest { + pub(crate) hex_bytes: String, +} + +#[derive(Deserialize, Serialize)] +pub(crate) struct AssetIdFromHexBytesResponse { + pub(crate) asset_id: String, +} + #[derive(Deserialize, Serialize)] pub(crate) struct AssetMetadataRequest { pub(crate) asset_id: String, @@ -1224,6 +1244,30 @@ pub(crate) async fn asset_balance( })) } +pub(crate) async fn asset_id_from_hex_bytes( + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + let hex_bytes = hex_str_to_vec(&payload.hex_bytes) + .ok_or_else(|| APIError::InvalidHexString(payload.hex_bytes))?; + + let contract_id = ContractId::copy_from_slice(&hex_bytes) + .map_err(|_| APIError::InvalidAssetIDBytes)?; + let asset_id = contract_id.to_string(); + + Ok(Json(AssetIdFromHexBytesResponse { asset_id })) +} + +pub(crate) async fn asset_id_to_hex_bytes( + WithRejection(Json(payload), _): WithRejection, APIError>, +) -> Result, APIError> { + + let contract_id = ContractId::from_str(&payload.asset_id) + .map_err(|_| APIError::InvalidAssetID(payload.asset_id))?; + let hex_bytes = hex_str(&contract_id.to_byte_array()); + + Ok(Json(AssetIdToHexBytesResponse { hex_bytes })) +} + pub(crate) async fn asset_metadata( State(state): State>, WithRejection(Json(payload), _): WithRejection, APIError>, @@ -1432,21 +1476,6 @@ pub(crate) async fn create_utxos( .await } -pub(crate) async fn decode_asset_id( - WithRejection(Json(payload), _): WithRejection, APIError>, -) -> Result, APIError> { - - let contract_id = ContractId::from_str(&payload.asset_id) - .map_err(|_| APIError::InvalidAssetID(payload.asset_id.clone()))?; - - let bytes: &[u8] = &contract_id[..]; - let hex_format = bytes.iter() - .map(|b| format!("{:02x}", b)) - .collect::(); - - Ok(Json(DecodeAssetIdResponse { hex_format, asset_id: payload.asset_id })) -} - pub(crate) async fn decode_ln_invoice( State(state): State>, WithRejection(Json(payload), _): WithRejection, APIError>, @@ -1537,35 +1566,6 @@ pub(crate) async fn disconnect_peer( .await } -pub(crate) async fn encode_asset_id( - WithRejection(Json(payload), _): WithRejection, APIError>, -) -> Result, APIError> { - if payload.hex_format.len() != 64 { - return Err(APIError::InvalidAssetID(format!( - "Hex format asset ID must be 64 characters, actual length: {}", - payload.hex_format.len() - ))); - } - - let hex_bytes = hex_str_to_vec(&payload.hex_format) - .ok_or_else(|| APIError::InvalidAssetID(format!( - "Invalid hex string: {}", - payload.hex_format - )))?; - - if hex_bytes.len() != 32 { - return Err(APIError::InvalidAssetID(format!( - "Contract ID must be 32 bytes, actual: {} bytes", - hex_bytes.len() - ))); - } - - let contract_id = ContractId::from(<[u8; 32]>::try_from(hex_bytes).unwrap()); - let asset_id = contract_id.to_string(); - - Ok(Json(EncodeAssetIdResponse { hex_format: payload.hex_format, asset_id })) -} - pub(crate) async fn estimate_fee( State(state): State>, WithRejection(Json(payload), _): WithRejection, APIError>, @@ -3642,28 +3642,3 @@ pub(crate) async fn unlock( }) .await } - - - -#[derive(Deserialize, Serialize)] -pub(crate) struct DecodeAssetIdRequest { - pub(crate) asset_id: String, -} - -#[derive(Deserialize, Serialize)] -pub(crate) struct DecodeAssetIdResponse { - pub(crate) hex_format: String, - pub(crate) asset_id: String, -} - -#[derive(Deserialize, Serialize)] -pub(crate) struct EncodeAssetIdRequest { - pub(crate) hex_format: String, -} - -#[derive(Deserialize, Serialize)] -pub(crate) struct EncodeAssetIdResponse { - pub(crate) hex_format: String, - pub(crate) asset_id: String, -} - diff --git a/src/test/asset_id_hex_bytes.rs b/src/test/asset_id_hex_bytes.rs new file mode 100644 index 0000000..5684743 --- /dev/null +++ b/src/test/asset_id_hex_bytes.rs @@ -0,0 +1,33 @@ +use super::*; + +const TEST_DIR_BASE: &str = "tmp/asset_id_hex_bytes/"; + +#[serial_test::serial] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[traced_test] +async fn success() { + initialize(); + + let test_dir_node1 = format!("{TEST_DIR_BASE}node1"); + let (node1_addr, _) = start_node(&test_dir_node1, NODE1_PEER_PORT, false).await; + + fund_and_create_utxos(node1_addr, None).await; + + // issue assets + let asset_cfa = issue_asset_cfa(node1_addr, None).await; + let asset_nia = issue_asset_nia(node1_addr).await; + let asset_uda = issue_asset_uda(node1_addr, None).await; + + // check + let cfa_decoded_result = asset_id_to_hex_bytes(node1_addr, asset_cfa.asset_id.clone()).await; + let nia_decoded_result = asset_id_to_hex_bytes(node1_addr, asset_nia.asset_id.clone()).await; + let uda_decoded_result = asset_id_to_hex_bytes(node1_addr, asset_uda.asset_id.clone()).await; + + let cfa_encoded_result = asset_id_from_hex_bytes(node1_addr, cfa_decoded_result.hex_bytes.clone()).await; + let nia_encoded_result = asset_id_from_hex_bytes(node1_addr, nia_decoded_result.hex_bytes.clone()).await; + let uda_encoded_result = asset_id_from_hex_bytes(node1_addr, uda_decoded_result.hex_bytes.clone()).await; + + assert_eq!(cfa_encoded_result.asset_id, asset_cfa.asset_id); + assert_eq!(nia_encoded_result.asset_id, asset_nia.asset_id); + assert_eq!(uda_encoded_result.asset_id, asset_uda.asset_id); +} diff --git a/src/test/encode_decode_asset_id.rs b/src/test/encode_decode_asset_id.rs deleted file mode 100644 index bbe2450..0000000 --- a/src/test/encode_decode_asset_id.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::*; - -const TEST_DIR_BASE: &str = "tmp/asset_id/"; - -#[serial_test::serial] -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] -#[traced_test] -async fn asset_id() { - initialize(); - - let amt = 5000; - let file_path = "README.md"; - - let test_dir_node1 = format!("{TEST_DIR_BASE}node1"); - let (node1_addr, _) = start_node(&test_dir_node1, NODE1_PEER_PORT, false).await; - - fund_and_create_utxos(node1_addr, None).await; - - // check /createutxos size parameter - let unspents_1 = list_unspents(node1_addr).await; - create_utxos(node1_addr, false, Some(1), Some(amt)).await; - let unspents_2 = list_unspents(node1_addr).await; - assert_eq!(unspents_1.len(), unspents_2.len() - 1); - assert!(!unspents_1.iter().any(|u| u.utxo.btc_amount == amt as u64)); - assert!(unspents_2.iter().any(|u| u.utxo.btc_amount == amt as u64)); - - // issue assets - let asset_cfa = issue_asset_cfa(node1_addr, Some(file_path)).await; - let asset_nia = issue_asset_nia(node1_addr).await; - let asset_uda = issue_asset_uda(node1_addr, Some(file_path)).await; - - // check - let cfa_decoded_result = decode_asset_id(node1_addr, asset_cfa.asset_id.clone()).await; - let nia_decoded_result = decode_asset_id(node1_addr, asset_nia.asset_id.clone()).await; - let uda_decoded_result = decode_asset_id(node1_addr, asset_uda.asset_id.clone()).await; - - let cfa_encoded_result = encode_asset_id(node1_addr, cfa_decoded_result.hex_format.clone()).await; - let nia_encoded_result = encode_asset_id(node1_addr, nia_decoded_result.hex_format.clone()).await; - let uda_encoded_result = encode_asset_id(node1_addr, uda_decoded_result.hex_format.clone()).await; - - assert_eq!(cfa_encoded_result.asset_id, asset_cfa.asset_id); - assert_eq!(nia_encoded_result.asset_id, asset_nia.asset_id); - assert_eq!(uda_encoded_result.asset_id, asset_uda.asset_id); -} diff --git a/src/test/mod.rs b/src/test/mod.rs index ff40541..8dec601 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -18,9 +18,9 @@ use tracing_test::traced_test; use crate::error::APIErrorResponse; use crate::ldk::FEE_RATE; use crate::routes::{ - address, asset_balance, asset_metadata, backup, btc_balance, change_password, + address, asset_balance, asset_id_to_hex_bytes, asset_id_from_hex_bytes, asset_metadata, backup, btc_balance, change_password, check_indexer_url, check_proxy_endpoint, close_channel, connect_peer, create_utxos, - decode_asset_id, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, encode_asset_id, estimate_fee, fail_transfers, + decode_ln_invoice, decode_rgb_invoice, disconnect_peer, estimate_fee, fail_transfers, get_asset_media, get_channel_id, get_payment, get_swap, 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, @@ -218,6 +218,40 @@ async fn asset_balance_spendable(node_address: SocketAddr, asset_id: &str) -> u6 asset_balance(node_address, asset_id).await.spendable } +async fn asset_id_from_hex_bytes(node_address: SocketAddr, hex_bytes: String) -> AssetIDFromHexBytesResponse { + println!("converting hex bytes {hex_bytes} to asset ID for node {node_address}"); + let payload = AssetIdFromHexBytesRequest { + hex_bytes, + }; + let res = reqwest::Client::new() + .post(format!("http://{}/assetidfromhexbytes", node_address)) + .json(&payload) + .send() + .await + .unwrap(); + _check_response_is_ok(res) + .await + .json::() + .await + .unwrap() +} + +async fn asset_id_to_hex_bytes(node_address: SocketAddr, asset_id: String) -> AssetIdToHexBytesResponse { + println!("converting asset ID {asset_id} to hex bytes for node {node_address}"); + let payload = AssetIdToHexBytesRequest { asset_id }; + let res = reqwest::Client::new() + .post(format!("http://{}/assetidtohexbytes", node_address)) + .json(&payload) + .send() + .await + .unwrap(); + _check_response_is_ok(res) + .await + .json::() + .await + .unwrap() +} + async fn backup(node_address: SocketAddr, backup_path: &str, password: &str) { println!("performing backup for node {node_address} on {backup_path}"); let payload = BackupRequest { @@ -384,24 +418,6 @@ async fn create_utxos(node_address: SocketAddr, up_to: bool, num: Option, si .unwrap(); } -async fn decode_asset_id(node_address: SocketAddr, asset_id: String) -> DecodeAssetIdResponse { - println!("decoding asset ID {asset_id} for node {node_address}"); - let payload = DecodeAssetIdRequest { - asset_id, - }; - let res = reqwest::Client::new() - .post(format!("http://{}/decodeassetid", node_address)) - .json(&payload) - .send() - .await - .unwrap(); - _check_response_is_ok(res) - .await - .json::() - .await - .unwrap() -} - async fn decode_ln_invoice(node_address: SocketAddr, invoice: &str) -> DecodeLNInvoiceResponse { println!("decoding LN invoice {invoice} for node {node_address}"); let payload = DecodeLNInvoiceRequest { @@ -456,24 +472,6 @@ async fn disconnect_peer(node_address: SocketAddr, peer_pubkey: &str) { .unwrap(); } -async fn encode_asset_id(node_address: SocketAddr, asset_id: String) -> EncodeAssetIdResponse { - println!("encoding asset ID {asset_id} for node {node_address}"); - let payload = EncodeAssetIdRequest { - hex_format: asset_id, - }; - let res = reqwest::Client::new() - .post(format!("http://{}/encodeassetid", node_address)) - .json(&payload) - .send() - .await - .unwrap(); - _check_response_is_ok(res) - .await - .json::() - .await - .unwrap() -} - async fn fail_transfers(node_address: SocketAddr, batch_transfer_idx: Option) -> bool { println!( "failing transfers, batch_transfer_idx {batch_transfer_idx:?} from node {node_address}" @@ -1684,6 +1682,7 @@ pub fn mock_fee(fee: u32) -> u32 { } } +mod asset_id_hex_bytes; mod backup_and_restore; mod close_coop_nobtc_acceptor; mod close_coop_other_side; @@ -1694,7 +1693,6 @@ mod close_force_nobtc_acceptor; mod close_force_other_side; mod close_force_standard; mod concurrent_btc_payments; -mod encode_decode_asset_id; mod fail_transfers; mod getchannelid; mod htlc_amount_checks; From eef9f9b54605a9d76f52a01f3f4a8920572bc005 Mon Sep 17 00:00:00 2001 From: ka Date: Sat, 14 Jun 2025 22:36:20 +0800 Subject: [PATCH 5/6] add test for assetid(to|from)hexbytes APIs (cargo fmt) --- src/main.rs | 18 +++++++++--------- src/routes.rs | 11 +++++------ src/test/asset_id_hex_bytes.rs | 9 ++++++--- src/test/mod.rs | 32 ++++++++++++++++++-------------- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2b02f3b..dc32cee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,15 +39,15 @@ use crate::args::LdkUserInfo; use crate::error::AppError; use crate::ldk::stop_ldk; use crate::routes::{ - address, asset_balance, asset_id_from_hex_bytes, asset_id_to_hex_bytes, asset_metadata, backup, btc_balance, change_password, - check_indexer_url, check_proxy_endpoint, close_channel, connect_peer, create_utxos, - decode_ln_invoice, decode_rgb_invoice, disconnect_peer, estimate_fee, fail_transfers, - get_asset_media, get_channel_id, get_payment, get_swap, 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, asset_id_from_hex_bytes, asset_id_to_hex_bytes, asset_metadata, backup, + btc_balance, change_password, check_indexer_url, check_proxy_endpoint, close_channel, + connect_peer, create_utxos, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, + estimate_fee, fail_transfers, get_asset_media, get_channel_id, get_payment, get_swap, 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}; diff --git a/src/routes.rs b/src/routes.rs index f06d677..166ecc6 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1249,22 +1249,21 @@ pub(crate) async fn asset_id_from_hex_bytes( ) -> Result, APIError> { let hex_bytes = hex_str_to_vec(&payload.hex_bytes) .ok_or_else(|| APIError::InvalidHexString(payload.hex_bytes))?; - - let contract_id = ContractId::copy_from_slice(&hex_bytes) - .map_err(|_| APIError::InvalidAssetIDBytes)?; + + let contract_id = + ContractId::copy_from_slice(&hex_bytes).map_err(|_| APIError::InvalidAssetIDBytes)?; let asset_id = contract_id.to_string(); - + Ok(Json(AssetIdFromHexBytesResponse { asset_id })) } pub(crate) async fn asset_id_to_hex_bytes( WithRejection(Json(payload), _): WithRejection, APIError>, ) -> Result, APIError> { - let contract_id = ContractId::from_str(&payload.asset_id) .map_err(|_| APIError::InvalidAssetID(payload.asset_id))?; let hex_bytes = hex_str(&contract_id.to_byte_array()); - + Ok(Json(AssetIdToHexBytesResponse { hex_bytes })) } diff --git a/src/test/asset_id_hex_bytes.rs b/src/test/asset_id_hex_bytes.rs index 5684743..3e5d531 100644 --- a/src/test/asset_id_hex_bytes.rs +++ b/src/test/asset_id_hex_bytes.rs @@ -23,9 +23,12 @@ async fn success() { let nia_decoded_result = asset_id_to_hex_bytes(node1_addr, asset_nia.asset_id.clone()).await; let uda_decoded_result = asset_id_to_hex_bytes(node1_addr, asset_uda.asset_id.clone()).await; - let cfa_encoded_result = asset_id_from_hex_bytes(node1_addr, cfa_decoded_result.hex_bytes.clone()).await; - let nia_encoded_result = asset_id_from_hex_bytes(node1_addr, nia_decoded_result.hex_bytes.clone()).await; - let uda_encoded_result = asset_id_from_hex_bytes(node1_addr, uda_decoded_result.hex_bytes.clone()).await; + let cfa_encoded_result = + asset_id_from_hex_bytes(node1_addr, cfa_decoded_result.hex_bytes.clone()).await; + let nia_encoded_result = + asset_id_from_hex_bytes(node1_addr, nia_decoded_result.hex_bytes.clone()).await; + let uda_encoded_result = + asset_id_from_hex_bytes(node1_addr, uda_decoded_result.hex_bytes.clone()).await; assert_eq!(cfa_encoded_result.asset_id, asset_cfa.asset_id); assert_eq!(nia_encoded_result.asset_id, asset_nia.asset_id); diff --git a/src/test/mod.rs b/src/test/mod.rs index 8dec601..f787293 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -18,15 +18,15 @@ use tracing_test::traced_test; use crate::error::APIErrorResponse; use crate::ldk::FEE_RATE; use crate::routes::{ - address, asset_balance, asset_id_to_hex_bytes, asset_id_from_hex_bytes, asset_metadata, backup, btc_balance, change_password, - check_indexer_url, check_proxy_endpoint, close_channel, connect_peer, create_utxos, - decode_ln_invoice, decode_rgb_invoice, disconnect_peer, estimate_fee, fail_transfers, - get_asset_media, get_channel_id, get_payment, get_swap, 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, asset_id_from_hex_bytes, asset_id_to_hex_bytes, asset_metadata, backup, + btc_balance, change_password, check_indexer_url, check_proxy_endpoint, close_channel, + connect_peer, create_utxos, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, + estimate_fee, fail_transfers, get_asset_media, get_channel_id, get_payment, get_swap, 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::{hex_str_to_vec, ELECTRUM_URL_REGTEST, PROXY_ENDPOINT_LOCAL}; @@ -218,11 +218,12 @@ async fn asset_balance_spendable(node_address: SocketAddr, asset_id: &str) -> u6 asset_balance(node_address, asset_id).await.spendable } -async fn asset_id_from_hex_bytes(node_address: SocketAddr, hex_bytes: String) -> AssetIDFromHexBytesResponse { +async fn asset_id_from_hex_bytes( + node_address: SocketAddr, + hex_bytes: String, +) -> AssetIDFromHexBytesResponse { println!("converting hex bytes {hex_bytes} to asset ID for node {node_address}"); - let payload = AssetIdFromHexBytesRequest { - hex_bytes, - }; + let payload = AssetIdFromHexBytesRequest { hex_bytes }; let res = reqwest::Client::new() .post(format!("http://{}/assetidfromhexbytes", node_address)) .json(&payload) @@ -236,7 +237,10 @@ async fn asset_id_from_hex_bytes(node_address: SocketAddr, hex_bytes: String) -> .unwrap() } -async fn asset_id_to_hex_bytes(node_address: SocketAddr, asset_id: String) -> AssetIdToHexBytesResponse { +async fn asset_id_to_hex_bytes( + node_address: SocketAddr, + asset_id: String, +) -> AssetIdToHexBytesResponse { println!("converting asset ID {asset_id} to hex bytes for node {node_address}"); let payload = AssetIdToHexBytesRequest { asset_id }; let res = reqwest::Client::new() From 670ea462aa04aa8671c0674addd97e6442a7c6fe Mon Sep 17 00:00:00 2001 From: luke Date: Mon, 16 Jun 2025 11:36:41 +0800 Subject: [PATCH 6/6] fix use bugs in mod --- src/test/mod.rs | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/test/mod.rs b/src/test/mod.rs index f787293..74037d6 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -18,15 +18,26 @@ use tracing_test::traced_test; use crate::error::APIErrorResponse; use crate::ldk::FEE_RATE; use crate::routes::{ - address, asset_balance, asset_id_from_hex_bytes, asset_id_to_hex_bytes, asset_metadata, backup, - btc_balance, change_password, check_indexer_url, check_proxy_endpoint, close_channel, - connect_peer, create_utxos, decode_ln_invoice, decode_rgb_invoice, disconnect_peer, - estimate_fee, fail_transfers, get_asset_media, get_channel_id, get_payment, get_swap, 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, + AddressResponse, AssetBalanceRequest, AssetBalanceResponse, AssetCFA, + AssetIdFromHexBytesRequest, AssetIdFromHexBytesResponse, AssetIdToHexBytesRequest, + AssetIdToHexBytesResponse, AssetNIA, AssetUDA, BackupRequest, BtcBalanceRequest, + BtcBalanceResponse, ChangePasswordRequest, Channel, CloseChannelRequest, ConnectPeerRequest, + CreateUtxosRequest, DecodeLNInvoiceRequest, DecodeLNInvoiceResponse, DecodeRGBInvoiceRequest, + DecodeRGBInvoiceResponse, DisconnectPeerRequest, EmptyResponse, FailTransfersRequest, + FailTransfersResponse, GetAssetMediaRequest, GetAssetMediaResponse, GetChannelIdRequest, + GetChannelIdResponse, GetPaymentRequest, GetPaymentResponse, GetSwapRequest, GetSwapResponse, + HTLCStatus, InitRequest, InitResponse, InvoiceStatus, InvoiceStatusRequest, + InvoiceStatusResponse, IssueAssetCFARequest, IssueAssetCFAResponse, IssueAssetNIARequest, + IssueAssetNIAResponse, IssueAssetUDARequest, IssueAssetUDAResponse, KeysendRequest, + KeysendResponse, LNInvoiceRequest, LNInvoiceResponse, ListAssetsRequest, ListAssetsResponse, + ListChannelsResponse, ListPaymentsResponse, ListPeersResponse, ListSwapsResponse, + ListTransactionsRequest, ListTransactionsResponse, ListTransfersRequest, ListTransfersResponse, + ListUnspentsRequest, ListUnspentsResponse, MakerExecuteRequest, MakerInitRequest, + MakerInitResponse, NetworkInfoResponse, NodeInfoResponse, OpenChannelRequest, + OpenChannelResponse, Payment, Peer, PostAssetMediaResponse, RefreshRequest, RestoreRequest, + RgbInvoiceRequest, RgbInvoiceResponse, SendAssetRequest, SendAssetResponse, SendBtcRequest, + SendBtcResponse, SendPaymentRequest, SendPaymentResponse, Swap, SwapStatus, TakerRequest, + Transaction, Transfer, UnlockRequest, Unspent, }; use crate::utils::{hex_str_to_vec, ELECTRUM_URL_REGTEST, PROXY_ENDPOINT_LOCAL}; @@ -221,7 +232,7 @@ async fn asset_balance_spendable(node_address: SocketAddr, asset_id: &str) -> u6 async fn asset_id_from_hex_bytes( node_address: SocketAddr, hex_bytes: String, -) -> AssetIDFromHexBytesResponse { +) -> AssetIdFromHexBytesResponse { println!("converting hex bytes {hex_bytes} to asset ID for node {node_address}"); let payload = AssetIdFromHexBytesRequest { hex_bytes }; let res = reqwest::Client::new()