-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactoring #431
base: main
Are you sure you want to change the base?
Refactoring #431
Conversation
WalkthroughThis pull request standardizes error handling and messaging across the codebase while refactoring many control flows. In Changes
Sequence Diagram(s)sequenceDiagram
participant M as Message
participant E as UnwrappedGift Event
participant DB as Database/Pool
participant O as Order
participant Q as Message Queue
M->>DB: Call get_order(msg)
DB-->>M: Return Order
M->>O: Check status (check_status)
alt Valid order status
O->>M: Validate sender pubkey (buyer/seller)
alt Pubkey valid
M->>Q: Enqueue order message (enqueue_order_msg)
M->>DB: Update order in database
else Invalid pubkey
M-->>M: Return error (MostroCantDo)
end
else Invalid status
M-->>M: Return error (MostroInternalErr)
end
sequenceDiagram
participant S as Scheduler
participant MQ as MESSAGE_QUEUES
participant DM as send_dm
S->>MQ: Retrieve queued messages
MQ-->>S: Return messages (queue_order_msg, queue_order_cantdo)
S->>DM: Process and send messages
DM-->>S: Confirm delivery
S->>MQ: Clear message queues
Possibly related PRs
Suggested reviewers
Poem
Tip 🌐 Web search-backed reviews and chat
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Hi @arkanoider cACK, I like it, let's go further with this implementation 🚀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (3)
src/app/release.rs (1)
213-246
: Review Outcome – Potential Issue in do_payment HandlingThe investigation confirms that in two locations (specifically, in src/app/release.rs and src/app/admin_settle.rs), the result of the asynchronous
do_payment
call is discarded by assigning it to_
. In contrast, src/scheduler.rs properly checks and logs errors fromdo_payment
. This inconsistency could obscure unexpected payment errors, especially if partial failures are critical to workflow integrity.
- src/app/release.rs:
do_payment(order, request_id).await
is assigned to_
, which discards its outcome.- src/app/admin_settle.rs: Similarly,
do_payment(order_updated, request_id).await
is ignored.- src/scheduler.rs: The function's error is explicitly checked and logged if the call fails.
Please review whether ignoring the outcome in the first two instances is intended or if further error handling/logging should be implemented.
🔗 Analysis chain
Consider verifying do_payment’s outcome.
do_payment(order, request_id).await
is called and its result is assigned to_
. If partial failures in payment logic are critical to your workflow, ensure that unexpected errors are handled or logged appropriately. Otherwise, ignoring the result might obscure possible failures.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Script to identify any place where `do_payment` is called # but its result is discarded in the codebase. rg 'do_payment\(.*\)' -A 2Length of output: 746
src/lightning/mod.rs (2)
149-167
: Standardize error mapping incancel_hold_invoice
.The error handling pattern in this function is inconsistent with the rest of the file. Line 161 maps the error to a string directly, while other functions use
MostroInternalErr
directly.Apply this diff to standardize the error handling:
let cancel = self .client .invoices() .cancel_invoice(cancel_message) .await - .map_err(|e| e.to_string()); + .map_err(|e| MostroInternalErr(ServiceError::LnNodeError(e.to_string()))); match cancel { Ok(cancel) => Ok(cancel.into_inner()), - Err(e) => Err(MostroInternalErr(ServiceError::LnNodeError(e.to_string()))), + Err(e) => Err(e), }
169-262
: Improve error handling consistency insend_payment
.The function uses different error types (
LnNodeError
andLnPaymentError
) inconsistently. Consider standardizing to useLnPaymentError
for all payment-related errors.Apply this diff to standardize the error handling:
listener .clone() .send(msg) .await - .map_err(|e| MostroInternalErr(ServiceError::LnNodeError(e.to_string())))? + .map_err(|e| MostroInternalErr(ServiceError::LnPaymentError(e.to_string())))?
🧹 Nitpick comments (32)
src/app/admin_add_solver.rs (3)
5-9
: Remove wildcard import
Usinguse mostro_core::error::{MostroError, ServiceError};
might be more explicit and avoids polluting the namespace with unused items.
45-47
: Consider logging underlying error
When converting from bech32, capturing the actual parsing error could aid debugging.- .map_err(|_| MostroInternalErr(ServiceError::InvalidPubkey))?; + .map_err(|e| MostroInternalErr(ServiceError::InvalidPubkey(e.to_string())))?;
55-57
: Preserve JSON serialization cause
Currently returning a genericMessageSerializationError
—consider inserting the underlying serialization error for better troubleshooting.src/app/take_buy.rs (3)
5-9
: Unified error handling
AdoptingMostroError::{self, *}
and removing usage ofanyhow::Result
fosters consistency. However, consider avoiding wildcard imports for clarity.
46-46
: Wrong amount error
MostroInternalErr(ServiceError::WrongAmountError)
may be better replaced with a user-facing error if the user provided an invalid amount rather than an internal configuration error.
60-62
: map_err overshadowing
Mapping errors fromget_buyer_pubkey()
toMostroInternalErr
alone might obscure important debug details.src/app/order.rs (2)
4-8
: Wildcard import caution
While including all variants ofMostroError
can be convenient, consider enumerating them for clarity and to avoid accidental collisions.
92-93
: Don't lose original error
.map_err(|_| MostroError::MostroInternalErr(ServiceError::InvalidOrderId))?;
discards the original error context. Includinge
could simplify debugging..map_err(|e| MostroError::MostroInternalErr( ServiceError::InvalidOrderId(format!("Invalid order: {}", e)) ))?;src/app/take_sell.rs (1)
17-39
:update_order_status
function
Centralizing the status update logic fosters improved readability and reusability. However, consider handling potentialunwrap()
on buyer_pubkey (line 24) more gracefully to avoid panics if an order is malformed.Here’s an optional diff to ensure robust error handling:
- let buyer_pubkey = order.get_buyer_pubkey().unwrap(); + let buyer_pubkey = match order.get_buyer_pubkey() { + Ok(pk) => pk, + Err(cause) => return Err(MostroCantDo(cause)), + };src/app/admin_settle.rs (1)
49-60
: Conditional check on cooperative cancellation.
ReturningMostroCantDo(IsNotYourDispute)
if the order is not cooperatively canceled might be confusing. Consider using a more specific reason, such asCantDoReason::InvalidOrderStatus
, for better clarity.-if order.check_status(Status::CooperativelyCanceled).is_err() { - return Err(MostroCantDo( - CantDoReason::IsNotYourDispute, - )); +if order.check_status(Status::CooperativelyCanceled).is_err() { + return Err(MostroCantDo(CantDoReason::InvalidOrderStatus)); }src/app/admin_cancel.rs (1)
49-60
: Cooperative cancellation validation.
Similar toadmin_settle.rs
, returningMostroCantDo(cause)
for mismatched status is valid, though consider ifcause
should be more descriptive (e.g.,InvalidOrderStatus
).src/app/rate_user.rs (1)
17-65
: New helper functionprepare_variables_for_vote
.
Creating a dedicated function to manage buyer/seller identification and error handling is a great step towards modularity. Consider returning a small struct instead of a tuple for enhanced readability and maintainability.-pub fn prepare_variables_for_vote(...) -> Result<(String, String, bool, bool), MostroError> { +#[derive(Debug)] +pub struct VoteVariables { + pub counterpart: String, + pub counterpart_trade_pubkey: String, + pub buyer_rating: bool, + pub seller_rating: bool, +} + +pub fn prepare_variables_for_vote(...) -> Result<VoteVariables, MostroError> { ... - Ok((counterpart, counterpart_trade_pubkey, buyer_rating, seller_rating)) + Ok(VoteVariables { + counterpart, + counterpart_trade_pubkey, + buyer_rating, + seller_rating, + }) }src/app/admin_take_dispute.rs (2)
114-116
: Preserve the underlying error message when serialization fails.
You're currently discarding the original error value by usingmap_err(|_| ...)
. Retaining the original error details can help with debugging.- .map_err(|_| MostroInternalErr(ServiceError::MessageSerializationError))?; + .map_err(|err| MostroInternalErr(ServiceError::MessageSerializationError( + err.to_string() + )))?;
152-160
: Consolidate repeated DM-sending logic.
The logic for sending direct messages to buyer and seller is almost duplicated. A helper function or shared method could reduce duplication and simplify future maintenance.Also applies to: 162-172
src/app/dispute.rs (1)
53-53
: Retain the original error context when creating dispute events.
You're discarding the details by usingmap_err(|_| ...)
; consider preserving the underlying error for easier debugging.- .map_err(|_| MostroInternalErr(ServiceError::DisputeEventError))?; + .map_err(|err| MostroInternalErr(ServiceError::DisputeEventError( + err.to_string() + )))?;src/app.rs (2)
293-293
: Consider handling the result ofcheck_trade_index
.
You're discarding the possible error fromcheck_trade_index
by assigning it to_
. This may obscure user feedback or diagnostics.- let _ = check_trade_index(&pool, &event, &message).await; + if let Err(err) = check_trade_index(&pool, &event, &message).await { + tracing::warn!("Trade index check error: {:?}", err); + // Optionally handle or escalate the error here + }
324-325
: Complete thetodo!()
block for error handling.
Atodo!()
indicates an unimplemented code path. Use an appropriate error variant or implement the necessary logic.Would you like help implementing this logic or returning a specialized error?
src/app/release.rs (1)
82-88
: Avoid repeated status checks.
These two blocks check the same set of statuses (Active, FiatSent, Dispute). Consider consolidating them into a single helper function or removing the duplication if only one check is needed here.- // Check if order is active, fiat sent or dispute - if order.check_status(Status::Active).is_err() && order.check_status(Status::FiatSent).is_err() - && order.check_status(Status::Dispute).is_err() - { - return Err(MostroCantDo(CantDoReason::NotAllowedByStatus)); - } ... (some lines later) ... - // Check if order is active, fiat sent or dispute - if order.check_status(Status::Active).is_err() && order.check_status(Status::FiatSent).is_err() - && order.check_status(Status::Dispute).is_err() - { - return Err(MostroCantDo(CantDoReason::NotAllowedByStatus)); - } + // Consider merging these checks into a single function or call: + fn ensure_valid_release_status(order: &Order) -> Result<(), MostroError> { + if order.check_status(Status::Active).is_err() + && order.check_status(Status::FiatSent).is_err() + && order.check_status(Status::Dispute).is_err() + { + return Err(MostroCantDo(CantDoReason::NotAllowedByStatus)); + } + Ok(()) + } + ensure_valid_release_status(&order)?;Also applies to: 97-102
src/app/cancel.rs (3)
70-185
: Complex cancellation logic could be simplified.
The code handlingWaitingPayment
vsWaitingBuyerInvoice
with maker/taker checks is sprawling. Consider extracting these checks into small helper functions (e.g.,is_cancellable_by_maker
,is_cancellable_by_taker
). This would reduce nesting, improve testability, and better convey intent.
282-360
: Unit tests recommended.
cancel_add_invoice
adds important logic around returning seller funds and reverting the order state. Currently, there's no direct test coverage for it. Automated tests would help ensure correctness, especially for edge cases (repeated calls, invalid pubkeys, etc.).Do you want me to provide a sample unit test you can adapt for verifying edge cases?
362-444
: Similar flows incancel_pay_hold_invoice
.
Likecancel_add_invoice
, thecancel_pay_hold_invoice
function has repeated logic for resetting the order. Consider extracting a shared helper to handle the revert-to-pending scenario.src/util.rs (4)
109-120
: Clear error handling for Yadio request.
ReturningMostroInternalErr(ServiceError::NoAPIResponse)
orNoCurrency
orMalformedAPIRes
neatly indicates the root cause. To reduce branching, consider combining repeated checks into a single match if the logic is invariably linear.
124-131
: Preserve JSON parsing errors for debugging.
When callingq.json::<Yadio>()
, you discard the original error detail. Including it in theMessageSerializationError
or logging it could greatly help debugging malformed responses.-.map_err(|_| MostroError::MostroInternalErr(ServiceError::MessageSerializationError))? +.map_err(|e| { + tracing::error!("Failed parsing Yadio response: {e}"); + MostroError::MostroInternalErr(ServiceError::MessageSerializationError) +})?
761-774
: Helpfulget_order
function.
This function neatly wraps DB lookups in a type-safe manner. It might be beneficial to mention which upstream code is responsible for verifying user ownership or permissions to access the returned order.
776-798
: Efficient invoice validation withvalidate_invoice
.
This is a nice modular approach. One minor suggestion: log invalid invoice details (at least partially or hashed) for troubleshooting, if not considered sensitive.src/app/trade_pubkey.rs (3)
12-16
: Consider adding documentation for the function parameters.While the function signature is clear, adding documentation for
msg
,event
, andpool
parameters would improve code maintainability.+/// Handles the trading of public keys between buyers and sellers +/// +/// # Arguments +/// * `msg` - The message containing the request details +/// * `event` - The unwrapped gift event containing sender information +/// * `pool` - The database connection pool +/// +/// # Returns +/// * `Result<(), MostroError>` - Success or a MostroError pub async fn trade_pubkey_action( msg: Message, event: &UnwrappedGift, pool: &Pool<Sqlite>, ) -> Result<(), MostroError> {
27-38
: Consider using early returns for better readability.The nested match pattern could be simplified using early returns, making the code more maintainable.
- match ( - order.master_buyer_pubkey.as_ref(), - order.master_seller_pubkey.as_ref(), - ) { - (Some(master_buyer_pubkey), _) if master_buyer_pubkey == &event.sender.to_string() => { - order.buyer_pubkey = Some(event.rumor.pubkey.to_string()); - } - (_, Some(master_seller_pubkey)) if master_seller_pubkey == &event.sender.to_string() => { - order.seller_pubkey = Some(event.rumor.pubkey.to_string()); - } - _ => return Err(MostroInternalErr(ServiceError::InvalidPubkey)), - }; + if let Some(master_buyer_pubkey) = order.master_buyer_pubkey.as_ref() { + if master_buyer_pubkey == &event.sender.to_string() { + order.buyer_pubkey = Some(event.rumor.pubkey.to_string()); + return Ok(()); + } + } + + if let Some(master_seller_pubkey) = order.master_seller_pubkey.as_ref() { + if master_seller_pubkey == &event.sender.to_string() { + order.seller_pubkey = Some(event.rumor.pubkey.to_string()); + return Ok(()); + } + } + + return Err(MostroInternalErr(ServiceError::InvalidPubkey));
52-55
: Consider adding error context for better debugging.The database error could include more context about what operation failed.
order .update(pool) .await - .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?; + .map_err(|e| MostroInternalErr(ServiceError::DbAccessError( + format!("Failed to update order {}: {}", order.id, e) + )))?;src/lnurl.rs (1)
20-34
: Consider adding error context for better debugging.While the error handling is correct, adding context about which validation failed would help with debugging.
let (user, domain) = match address.split_once('@') { Some((user, domain)) => (user, domain), - None => return Err(MostroInternalErr(ServiceError::LnAddressParseError)), + None => return Err(MostroInternalErr(ServiceError::LnAddressParseError( + format!("Invalid lightning address format: {}", address) + ))), };src/flow.rs (1)
90-98
: Consider grouping related messages for better maintainability.The buyer and seller messages could be grouped into a helper function for better code organization.
+async fn send_order_messages( + request_id: Option<u64>, + order_id: i64, + buyer_action: Action, + seller_action: Action, + order_data: Option<Payload>, + buyer_pubkey: PublicKey, + seller_pubkey: PublicKey, +) { + enqueue_order_msg( + request_id, + Some(order_id), + buyer_action, + order_data, + buyer_pubkey, + None, + ).await; + + enqueue_order_msg( + request_id, + Some(order_id), + seller_action, + None, + seller_pubkey, + None, + ).await; +}Also applies to: 101-109
src/lightning/invoice.rs (1)
11-17
: Consider adding specific error messages for better debugging.While the error handling is correct, adding context about why the invoice is invalid would help with debugging.
let invoice = Bolt11Invoice::from_str(payment_request) - .map_err(|_| MostroInternalErr(ServiceError::InvoiceInvalidError))?; + .map_err(|e| MostroInternalErr(ServiceError::InvoiceInvalidError( + format!("Failed to parse invoice: {}", e) + )))?;src/main.rs (1)
37-45
: Consider adding documentation for the message queue system.The new message queue system is a critical component for handling various types of messages. Please add documentation to explain:
- The purpose and lifecycle of each queue type
- The thread-safety guarantees provided by the implementation
- The expected message flow and processing patterns
+/// A thread-safe container for managing different types of message queues in the system. +/// +/// # Fields +/// * `queue_order_msg` - Queue for regular order-related messages +/// * `queue_order_cantdo` - Queue for order rejection/failure messages +/// * `queue_order_rate` - Queue for order rating events #[derive(Debug, Clone, Default)] pub struct MessageQueues { pub queue_order_msg: Arc<Mutex<Vec<(Message, PublicKey)>>>, pub queue_order_cantdo: Arc<Mutex<Vec<(Message, PublicKey)>>>, pub queue_order_rate: Arc<Mutex<Vec<Event>>>, } +/// Global instance of message queues, lazily initialized and protected by a read-write lock. static MESSAGE_QUEUES: LazyLock<RwLock<MessageQueues>> = LazyLock::new(|| RwLock::new(MessageQueues::default()));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Cargo.lock
is excluded by!**/*.lock
📒 Files selected for processing (25)
Cargo.toml
(1 hunks)src/app.rs
(7 hunks)src/app/add_invoice.rs
(1 hunks)src/app/admin_add_solver.rs
(3 hunks)src/app/admin_cancel.rs
(5 hunks)src/app/admin_settle.rs
(4 hunks)src/app/admin_take_dispute.rs
(6 hunks)src/app/cancel.rs
(5 hunks)src/app/dispute.rs
(6 hunks)src/app/fiat_sent.rs
(1 hunks)src/app/order.rs
(2 hunks)src/app/rate_user.rs
(8 hunks)src/app/release.rs
(10 hunks)src/app/take_buy.rs
(1 hunks)src/app/take_sell.rs
(1 hunks)src/app/trade_pubkey.rs
(1 hunks)src/db.rs
(1 hunks)src/error.rs
(0 hunks)src/flow.rs
(3 hunks)src/lightning/invoice.rs
(6 hunks)src/lightning/mod.rs
(12 hunks)src/lnurl.rs
(1 hunks)src/main.rs
(3 hunks)src/scheduler.rs
(4 hunks)src/util.rs
(17 hunks)
💤 Files with no reviewable changes (1)
- src/error.rs
✅ Files skipped from review due to trivial changes (1)
- src/db.rs
🔇 Additional comments (122)
src/app/admin_add_solver.rs (4)
2-2
: No concerns
New usage ofsend_dm
is consistent with your approach to direct messaging.
21-21
: Consistent error type
ReturningResult<(), MostroError>
aligns with your new error handling approach across the codebase.
42-42
: Confirm error type
You're returning aMostroInternalErr
for an invalid pubkey. Consider whether this scenario is purely internal or if a user-friendly error (MostroCantDo
) might be more appropriate.
60-62
: Good approach
Usingmap_err
withMostroInternalErr
insend_dm
ensures unified error handling for potential Nostr-specific failures.src/app/take_buy.rs (8)
2-2
: Helpful utility usage
Adding references toget_fiat_amount_requested
,get_market_amount_and_fee
,get_order
, andshow_hold_invoice
aligns well with your refactoring efforts.
20-20
: Harmonized return type
ReturningResult<(), MostroError>
fits the new approach of explicit error handling.
23-23
: Verifyget_order
usage
get_order(&msg, pool).await?
might fail if the order doesn't exist or is invalid. Confirm that scenarios where the order is missing are handled elsewhere or tested comprehensively.
28-34
: Properly blocking invalid orders
UsingMostroCantDo(cause)
if the order isn't a buy or hasn't pending status is a straightforward approach that informs the user appropriately.
37-40
: Security measure
Ensuring the event is from the original maker prevents unauthorized manipulation of the order. Good practice.
49-57
: Market amount fallback
Falling back toget_market_amount_and_fee()
for a zero-amount order is sensible, but confirm that invalid or unavailable exchange rates are surfaced to the user appropriately.
68-69
: Timestamping
order.set_timestamp_now();
ensures the take action is recorded—this is a good approach for order tracking.
71-85
: Consistent user feedback
Allshow_hold_invoice
failures become internal errors. Verify if any scenario could be more informative to end users, for instance, a "can't do" message if invoice creation fails due to user input.src/app/order.rs (7)
2-2
: Centralized invoice validation
Importingvalidate_invoice
along with other related utilities consolidates invoice handling logic neatly.
9-10
: Expanded core references
ImportingMessage
,Order
, andSmallOrder
indicates enhanced utility for multiple order operations in this module.
55-55
: Unified error type
-> Result<(), MostroError>
improves consistency across the system, making error handling more predictable.
60-61
: Direct invoice validation
validate_invoice(&msg, &Order::from(order.clone())).await?
is a neat approach; ensure partial or malformed invoices yield clear user feedback.
67-69
: Range order limits
UsingMostroCantDo
ifcheck_range_order_limits
fails gives the user explicit feedback on invalid range requests.
71-73
: Zero amount with premium
Rejecting an order that sets an impossible premium with zero amount is sensible.
78-78
: Quote validation
Invokingcalculate_and_check_quote
for each fiat amount ensures robust verification of multi-amount orders.src/app/fiat_sent.rs (13)
1-9
: Imports look consistent with new error handling and queue utilities.
They align well with the refactoring goals of centralizing error definitions inmostro_core::error
and usingenqueue_order_msg
for message dispatch.
15-15
: Doc comment addition is clear.
The new comment clarifies this function's purpose without affecting logic.
21-23
: ReturningResult<(), MostroError>
is consistent with the project's new error strategy.
This signature change follows the refactoring scope: any function that may fail should return aMostroError
.
25-26
: Status validation is appropriate.
ReturningMostroCantDo
for invalid statuses ensures consistent error semantics.
31-32
: Buyer identity check.
Verifyingorder.get_buyer_pubkey()
matchesevent.rumor.pubkey
prevents mismatched ownership. Good approach.
35-39
: Careful handling of next trade key.
Graceful fallback toNone
or returningMostroInternalErr
helps avoid undefined states.
44-46
: Order and event update integration.
Mapping errors to an internal error type makes the flow consistent with the newMostroError
scheme.
48-51
: Database update error handling is well-defined.
Usingmap_err
ensures that anysqlx
failure is translated into aMostroInternalErr
.
54-54
: Seller pubkey retrieval is correct.
Mapping any retrieval error directly toMostroInternalErr
is consistent.
60-65
: Enqueuing seller message.
This centralized queuing approach fits the PR's goal of simplifying message dispatch.
72-77
: Buyer notification logic.
Similar to the seller, properly enqueued with minimal duplication.
84-96
: Synchronized next trade handling.
Updatingnext_trade_pubkey
andnext_trade_index
only after verifying thesent_from_maker
condition is a solid approach.
98-99
: Final return.
Function cleanly concludes withOk(())
, maintaining consistent error-handling patterns.src/app/add_invoice.rs (18)
1-3
: New import references for invoice validation.
Bringingvalidate_invoice
into scope aligns with the refactor that centralizes invoice checks.
5-5
: Use ofanyhow::Result
replaced byMostroError
below.
Retaininganyhow::Result
for local convenience is fine, given final errors map toMostroError
.
7-11
: Consolidated error and order modules.
Imports group relevant modules (MostroCantDo
,ServiceError
,Status
, etc.) for the new approach.
17-45
:check_order_status
function fosters clarity and modularity.
It encapsulates status checks and messages, reducing duplication inadd_invoice_action
. Good reusability.
52-54
: ReturningResult<(), MostroError>
inadd_invoice_action
.
Consistent with the application-wide change to unify error handling types.
56-58
: Validating order status.
Mapping the status fetch failure to an internal error ensures uniform error propagation.
60-63
: Validating order kind is essential.
ReturningMostroInternalErr
enforces consistent error semantics.
65-66
: Buyer public key resolution.
Gracefully propagates any data retrieval failure throughMostroInternalErr
.
69-70
: Restricting add-invoice action to buyer only.
Rejecting mismatched pubkeys asMostroCantDo
is correct for user-facing error messages.
73-74
:validate_invoice
usage.
Offers a neat encapsulation for invoice correctness checks, now integrated with the main logic.
76-77
: Delegating status check tocheck_order_status
.
Enhances readability by separating status logic from main invoice flow.
78-79
: Seller pubkey retrieval.
Fetching the counterpart's pubkey with error mapping is consistent with the new pattern.
83-84
: Creating a smallerSmallOrder
struct.
This smaller variant is beneficial for message dispatch, reducing data overhead.
86-88
: Replacing the order event.
Uses the same approach seen in other modules to keep order data in sync with on-chain/off-chain changes.
90-100
: Enqueuing message for seller.
Refactor fromsend_new_order_msg
toenqueue_order_msg
unifies messaging in the codebase.
101-110
: Enqueuing message for buyer.
Mirrors the seller logic, ensuring both parties remain informed at each stage.
110-119
: Fallback toshow_hold_invoice
for missing preimage.
Properly extends the same error handling strategy, returningMostroInternalErr
on failure.
124-125
: Conclusion ofadd_invoice_action
.
The function ends cleanly withOk(())
, fulfilling the new error pattern.src/app/take_sell.rs (14)
2-3
: New utility imports.
Includingvalidate_invoice
andget_fiat_amount_requested
centralizes order data retrieval and invoice checks.
6-11
: Errors consolidated underMostroError
andServiceError
plus order definitions.
This import strategy is consistent with the shift to typed error returns.
41-46
: Updated signature to returnResult<(), MostroError>
.
Aligns with the new approach for typed error handling within the application.
48-49
: Order retrieval.
Pulling order from the database viaget_order
is consistent with the rest of the refactor.
53-60
: Ensuring it's asell
order and inPending
status.
ReturningMostroCantDo
for user-facing rejections preserves uniform error semantics.
62-65
: Validates the maker identity.
Requiring that theevent.rumor.pubkey
match ensures only the original maker can finalize the order.
67-67
: Fetching seller pubkey.
Maps potential errors toMostroInternalErr
, consistent with the approach in other modules.
70-70
: Invoice validation viavalidate_invoice
.
Streamlines the logic by delegating invoice checks to a single utility function.
77-77
: ReturningMostroInternalErr
for a wrong amount.
Ensures the function terminates gracefully when the user-submitted or derived fiat amount is invalid.
81-81
: Populating the buyer’s pubkey.
Ensures the order data remains consistent with the actual user taking the sell offer.
87-87
: Timestamp update.
Captures the time at which the buyer interacts with the order. Fits the new logic for tracking.
90-98
: Market-based amount and fee checks.
This is a convenient approach to handle unfilledamount
through external logic inget_market_amount_and_fee
.
100-106
: Branch when no payment request is present.
Callsupdate_order_status
to setWaitingBuyerInvoice
, simplifying the flow for late invoice provisioning.
109-123
: Showing a hold invoice if payment request exists.
This fallback suitably handles the invoice interaction, with consistent error mapping toMostroInternalErr
.src/app/admin_settle.rs (16)
5-5
: Imports updated to align with refactored helpers.
The inclusion ofenqueue_order_msg
,get_nostr_client
,get_order
,settle_seller_hold_invoice
, andupdate_order_event
in one place is consistent with the PR’s goal of centralizing logic and improving readability.
9-10
: Explicit error imports for clarity.
Using theMostroError
variants andServiceError
fosters more expressive error handling and keeps error definitions centralized.
28-28
: Refined return type for improved error reporting.
Changing the function signature to returnResult<(), MostroError>
instead of a genericResult<()>
adds clarity and consistency.
31-32
: Centralized order retrieval.
Switching toget_order
is a clean approach, ensuring uniform access to order data and simplifying error management.
34-38
: Solver assignment verification.
This block neatly checks whether the user handling the dispute is indeed the assigned solver. Good use ofMostroCantDo(IsNotYourDispute)
to clarify unauthorized access attempts.
41-43
: Database access errors are properly wrapped.
Converting the database error intoMostroInternalErr(ServiceError::DbAccessError)
clarifies the nature of DB failures and simplifies error propagation.
65-67
: Dispute status enforcement.
Ensuring the order is inDispute
state before proceeding helps avoid unintended flows. This is a solid guard clause.
68-71
: Seller hold invoice settlement.
Callingsettle_seller_hold_invoice
with a specializedAction::AdminSettled
accurately reflects the administrative override. Good usage of the new error type.
72-75
: Consistent event update after invoice settlement.
Leveragingupdate_order_event
withStatus::SettledHoldInvoice
maintains uniform status transitions and clear event history.
78-78
: Potential silent failure when fetching dispute.
Iffind_dispute_by_order_id
fails, the code silently ignores that error. Consider logging or explicitly handling the error to maintain clear visibility into DB issues.
84-86
: Dispute update with robust error handling.
Wrapping DB update errors underMostroInternalErr(ServiceError::DbAccessError(...))
ensures clarity when diagnosing dispute-related failures.
104-105
: Constructing Nostr event with meaningful error checks.
Wrapping potential Nostr errors intoMostroInternalErr(ServiceError::NostrError(...))
is a good approach to unify error reporting.
118-128
: Message dispatch to the event creator.
Centralizing calls toenqueue_order_msg
aligns with the PR objective of unifying message handling logic.
130-142
: Seller notification viaenqueue_order_msg
.
Parsing theseller_pubkey
and mapping any parse error toInvalidPubkey
is straightforward and consistent with other error flows.
143-155
: Buyer notification mirrored to seller flow.
Reusing the same pattern for the buyer ensures consistency, avoids code duplication, and cleanly handles pubkey parsing.
158-159
: Ignoring the result ofdo_payment
.
Storingdo_payment(...)
into_
swallows any potential errors. If payments occasionally fail, consider handling or logging the outcome for greater transparency.src/app/admin_cancel.rs (14)
7-7
: Extended utility imports for centralized message handling.
Integratingenqueue_order_msg
,get_order
, andupdate_order_event
supports the PR’s aim of unifying helper calls.
10-14
: Expanded error variants for precise problem reporting.
IntroducingCantDoReason
and distinctMostroError
types (e.g.,MostroCantDo
,MostroInternalErr
) clarifies error origin and severity.
29-29
: Method signature clarified withResult<(), MostroError>
.
Propagating domain-specific error types elevates code maintainability and debugging clarity.
33-33
: Consistent order retrieval.
get_order
systematically fetches the order, matching the approach across the codebase.
35-37
: Immediate solver assignment check.
ReturningMostroCantDo(CantDoReason::IsNotYourDispute)
quickly halts unauthorized actions, promoting security.
40-43
: Proper DB error wrapping.
UsingMostroInternalErr(ServiceError::DbAccessError(e.to_string()))
ensures that database issues are uniformly handled.
63-65
: Dispute check ensures correct workflow.
Restricting actions for a disputed order helps avoid conflicting states.
76-76
: Potential silent error for dispute retrieval.
If the retrieval fails, theOk(...)
pattern is not triggered, leaving an error unchecked. Consider adding logs for debugging.
82-84
: Dispute update with robust DB error conversion.
This maintains consistency with the rest of the system’s error management.
101-103
: Creating a new Nostr event for dispute status.
Wrapping potential Nostr errors inMostroInternalErr(ServiceError::NostrError(...))
is a clear, consistent approach.
116-122
: Order event update.
Updating both the event in Nostr and the local DB withCanceledByAdmin
thoroughly reflects the final state.
127-128
: Trade index usage.
Ensuring the correcttrade_index
is passed along preserves traceability for front-end recipients or logs.
144-150
: Seller/buyer pubkey parsing.
ReturningMostroInternalErr(ServiceError::InvalidPubkey)
on parse failure is more explicit than older generic errors, improving debug speed.
152-157
: Direct messaging the parties.
Usingsend_dm
for admin, seller, and buyer not only improves clarity but also aligns with the new unified error approach.src/app/rate_user.rs (15)
1-1
: Unified helpers for rating logic.
Pulling inenqueue_order_msg
andget_order
harmonizes the approach to message dispatch and data retrieval.
5-5
: Transition away from genericanyhow::Result
.
Thoughanyhow::Result
remains in scope, shifting toMostroError
in function signatures fosters domain-centric error handling.
6-8
: Expanded error coverage for rating process.
ImportingMostroError
,CantDoReason
, andServiceError
ensures the code can differentiate between user-facing and internal failures.
67-98
: Refined user reputation fetching.
Switching to-> Result<Option<Rating>, MostroError>
allows consistent error handling across external calls (e.g., Nostr). Sorting events by creation time ensures the latest rating is returned.
105-105
: Specific error type for rating updates.
UtilizingResult<(), MostroError>
clarifies that rating failures are part of a well-defined error domain.
106-107
: Single call for uniform order retrieval.
get_order(&msg, pool)
usage furthers the goal of consistent data access and error reporting.
109-111
: Status check ensures the order succeeded.
Rejecting attempts to rate an incomplete or invalid order withInvalidOrderStatus
helps avoid inconsistent data.
114-116
: Variable extraction for rating.
prepare_variables_for_vote
is invoked here, providing a clean separation of logic.
131-135
: Safe retrieval of user-supplied rating.
Theget_rating()
function call is gracefully wrapped withmap_err(MostroInternalErr)
, ensuring rating data is validated.
138-141
: Database check for user presence.
is_user_present
plus descriptive error mapping ensures that an invalid or non-existent user flow is handled predictably.
143-143
: Adjusting rating on the found user record.
user_to_vote.update_rating(new_rating)
elegantly modifies user stats in memory before persisting.
153-154
: Rating tagging logic.
to_tags()
method and associated error handling unify the rating data structure with Nostr’s event-based model.
168-171
: Detailed DB update error context.
Embedding the specific DB error string inServiceError::DbAccessError
is beneficial for debugging.
181-191
: Precise error handling when updating rating event.
Wrapping potential DB issues underMostroInternalErr(ServiceError::DbAccessError(...))
maintains a consistent error approach across the codebase.
194-202
: Final rating acknowledgment message.
PostingRateReceived
promptly notifies the user that the rating was successfully processed. Including thePayload::RatingUser(new_rating)
is a clean way to convey relevant data.src/app/admin_take_dispute.rs (1)
3-3
: Imports and updated function signature look good!
No major issues identified with the new imports, updated function signature, or error definitions.Also applies to: 6-10, 47-47
src/app/dispute.rs (1)
10-11
: Overall error handling refactor looks consistent.
No major issues identified in these changed lines. The new error types and usage appear correct.Also applies to: 12-18, 19-19, 69-69, 74-74, 84-88, 93-93, 101-101, 103-103, 105-109, 129-129, 136-136, 139-139, 150-152, 156-160, 165-166, 169-172, 177-178, 182-188, 193-198, 200-207, 210-212
src/app.rs (1)
18-19
: General improvements are correct.
No major issues found in these line changes. The new module references and refined error handling match the broader refactoring goals.Also applies to: 33-33, 39-39, 44-48, 53-53, 70-82, 97-99, 107-112, 131-132, 159-166, 170-178, 182-185, 189-190, 193-196, 197-201, 202-203, 205-207, 307-323
src/app/release.rs (1)
24-28
: Good introduction ofcheck_failure_retries
.
This function decouples the retry logic from the main payment flow, improving maintainability. Consider adding a short doc example that clarifies how retry counts are persisted and how clients should interpret partial retry attempts.src/app/cancel.rs (1)
35-39
: Properly preventing redundant cancellations.
ReturningMostroCantDo(CantDoReason::OrderAlreadyCanceled)
is clear and straightforward. This prevents confusion over canceled orders being canceled again.src/util.rs (2)
178-201
: Validate partial failures inpublish_order
.
If database insertion succeeds (lines 196–201) but publishing the Nostr event fails, you could end up with inconsistent states. Consider implementing a rollback or additional logging to handle partial failures.
353-385
: Event queue approach for rating updates looks neat.
Offloading Nostr event emission viaMESSAGE_QUEUES
is a clean pattern. Ensure concurrency on rating updates is tested, especially if multiple rating requests can happen simultaneously.src/app/trade_pubkey.rs (1)
1-11
: LGTM! Clean and well-organized imports.The imports are logically grouped and necessary for the functionality.
src/lnurl.rs (1)
8-8
: LGTM! Clean error type imports.The error type imports are well-organized and follow the new error handling strategy.
src/flow.rs (1)
63-71
: LGTM! Consistent message handling.The transition to
enqueue_order_msg
improves message handling consistency.Also applies to: 73-81
src/lightning/invoice.rs (1)
96-105
: LGTM! Well-structured test case.The test case is clear and properly validates the error handling.
Cargo.toml (2)
54-55
: Review the use of local path dependency.Using a local path for
mostro-core
in production could cause issues. This should be temporary for development/testing only.Please confirm:
- Is this patch intended for development only?
- Should it be removed before deploying to production?
- Are there plans to publish the local changes to crates.io?
41-47
: Verify the impact of downgrading mostro-core.The downgrade from version 0.6.25 to 0.6.23 could affect the error handling changes. Also, the
openssl
dependency has been commented out.Run the following script to check for breaking changes:
|
||
async fn calculate_and_check_quote( | ||
order: &SmallOrder, | ||
fiat_amount: &i64, | ||
) -> Result<(), MostroError> { | ||
// Get mostro settings | ||
let mostro_settings = Settings::get_mostro(); | ||
// Calculate quote | ||
let quote = match order.amount { | ||
0 => match get_bitcoin_price(&order.fiat_code) { | ||
Ok(price) => { | ||
let quote = *fiat_amount as f64 / price; | ||
(quote * 1E8) as i64 | ||
} | ||
Err(_) => { | ||
return Err(MostroInternalErr(ServiceError::NoAPIResponse)); | ||
} | ||
}, | ||
_ => order.amount, | ||
}; | ||
|
||
// Check amount is positive - extra safety check | ||
if quote < 0 { | ||
return Err(MostroCantDo(CantDoReason::InvalidAmount)); | ||
} | ||
|
||
if quote > mostro_settings.max_order_amount as i64 | ||
|| quote < mostro_settings.min_payment_amount as i64 | ||
{ | ||
return Err(MostroCantDo(CantDoReason::OutOfRangeSatsAmount)); | ||
} | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Potential floating-point precision issues
calculate_and_check_quote
casts a floating value multiplied by 1E8 into an i64
. Consider using fixed-decimal or rational arithmetic to avoid floating-point rounding problems in financial calculations.
async fn job_flush_messages_queue() { | ||
// Clone for closure owning with Arc | ||
let order_msg_list = MESSAGE_QUEUES.read().await.queue_order_msg.clone(); | ||
let cantdo_msg_list = MESSAGE_QUEUES.read().await.queue_order_cantdo.clone(); | ||
|
||
// Spawn a new task to flush the messages queue | ||
tokio::spawn(async move { | ||
loop { | ||
// Send message to event creator | ||
for message in order_msg_list.lock().await.iter() { | ||
info!("Flushing order messages in queue"); | ||
let destination_key = message.1; | ||
if let Ok(message) = message.0.as_json() { | ||
let sender_keys = crate::util::get_keys().unwrap(); | ||
let _ = send_dm(destination_key, sender_keys, message, None).await; | ||
} | ||
} | ||
for message in cantdo_msg_list.lock().await.iter() { | ||
info!("Flushing cant do messages in queue"); | ||
let destination_key = message.1; | ||
if let Ok(message) = message.0.as_json() { | ||
let sender_keys = crate::util::get_keys().unwrap(); | ||
let _ = send_dm(destination_key, sender_keys, message, None).await; | ||
} | ||
} | ||
// Clear the queues | ||
cantdo_msg_list.lock().await.clear(); | ||
order_msg_list.lock().await.clear(); | ||
|
||
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; | ||
} | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance message queue processing reliability.
The message queue processing implementation has several areas for improvement:
- No error handling for message sending failures
- No backoff strategy for failed messages
- No batching for efficient processing
- No metrics for monitoring queue sizes and processing rates
Consider implementing these improvements:
async fn job_flush_messages_queue() {
// Clone for closure owning with Arc
let order_msg_list = MESSAGE_QUEUES.read().await.queue_order_msg.clone();
let cantdo_msg_list = MESSAGE_QUEUES.read().await.queue_order_cantdo.clone();
// Spawn a new task to flush the messages queue
tokio::spawn(async move {
+ let mut consecutive_failures = 0;
loop {
+ let start_time = std::time::Instant::now();
+ let mut processed = 0;
+ let mut failed = 0;
+
// Send message to event creator
for message in order_msg_list.lock().await.iter() {
info!("Flushing order messages in queue");
let destination_key = message.1;
if let Ok(message) = message.0.as_json() {
let sender_keys = crate::util::get_keys().unwrap();
- let _ = send_dm(destination_key, sender_keys, message, None).await;
+ match send_dm(destination_key, sender_keys, message, None).await {
+ Ok(_) => {
+ processed += 1;
+ consecutive_failures = 0;
+ }
+ Err(e) => {
+ error!("Failed to send message: {}", e);
+ failed += 1;
+ consecutive_failures += 1;
+ }
+ }
}
}
// Similar changes for cantdo_msg_list...
// Clear the queues
cantdo_msg_list.lock().await.clear();
order_msg_list.lock().await.clear();
- tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
+ // Log metrics
+ let elapsed = start_time.elapsed();
+ info!(
+ "Message queue metrics - Processed: {}, Failed: {}, Duration: {:?}",
+ processed, failed, elapsed
+ );
+
+ // Implement exponential backoff on consecutive failures
+ let delay = if consecutive_failures > 0 {
+ std::cmp::min(
+ 1 << consecutive_failures,
+ 60 // Max delay of 60 seconds
+ )
+ } else {
+ 1
+ };
+ tokio::time::sleep(tokio::time::Duration::from_secs(delay)).await;
}
});
}
Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/app/fiat_sent.rs (1)
81-96
: Consider extracting the next trade fields update logic.The next trade fields update logic could be moved to a separate function for better maintainability.
+async fn update_next_trade_fields( + order: &mut Order, + next_trade: Option<(String, u32)>, + pool: &Pool<Sqlite>, +) -> Result<(), MostroError> { + if let Some((pubkey, index)) = next_trade { + order.next_trade_pubkey = Some(pubkey); + order.next_trade_index = Some(index as i64); + order.update(pool) + .await + .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?; + } + Ok(()) +}src/app/release.rs (2)
212-284
: Consider extracting payment status handling logic.The payment status handling logic in
do_payment
is complex and could be extracted into separate functions for better readability and maintainability.+async fn handle_payment_status( + status: PaymentStatus, + order: &mut Order, + msg: PaymentUpdate, + buyer_pubkey: PublicKey, + my_keys: &Keys, + request_id: Option<u64>, +) -> Result<()> { + match status { + PaymentStatus::Succeeded => { + info!( + "Order Id {}: Invoice with hash: {} paid!", + order.id, msg.payment.payment_hash + ); + payment_success(order, buyer_pubkey, my_keys, request_id).await?; + } + PaymentStatus::Failed => { + info!( + "Order Id {}: Invoice with hash: {} has failed!", + order.id, msg.payment.payment_hash + ); + if let Ok(failed_payment) = check_failure_retries(order, request_id).await { + info!( + "Order id {} has {} failed payments retries", + failed_payment.id, failed_payment.payment_attempts + ); + } + } + _ => {} + } + Ok(()) +}
436-442
: Consider consolidating duplicate message sending logic.The message sending logic in
notify_invalid_amount
is duplicated for buyer and seller. Consider consolidating it into a single function.+async fn send_invalid_amount_message( + request_id: Option<u64>, + order_id: uuid::Uuid, + pubkey: PublicKey, +) { + enqueue_cant_do_msg( + request_id, + Some(order_id), + CantDoReason::InvalidAmount, + pubkey, + ) + .await; +}Also applies to: 444-450
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/fiat_sent.rs
(1 hunks)src/app/release.rs
(10 hunks)
🔇 Additional comments (4)
src/app/fiat_sent.rs (4)
1-7
: LGTM! Clean imports organization.The imports are well-organized, with clear separation between internal and external dependencies.
15-21
: LGTM! Function signature updated for better error handling.The return type change from
Result<()>
toResult<(), MostroError>
improves error specificity.
35-39
: LGTM! Improved error handling for next trade key.The error handling is now more specific with
map_err(MostroInternalErr)
.
25-33
: Verify buyer's public key validation.The code checks if the pubkey matches the buyer, but consider adding logging before returning the error to help with debugging.
if order.get_buyer_pubkey().ok() != Some(event.rumor.pubkey) { + tracing::debug!("Invalid pubkey: expected {:?}, got {:?}", order.get_buyer_pubkey().ok(), event.rumor.pubkey); return Err(MostroCantDo(CantDoReason::InvalidPubkey)); }
✅ Verification successful
I'll start by checking if there is an existing logging statement for the buyer's public key validation in the file. This will help us determine whether the suggested logging should be added. For example, we can search for any usage of
tracing::debug
withinsrc/app/fiat_sent.rs
.
Action: Add debug logging for buyer's public key validation
The search confirms that no debug logging is present in the buyer pubkey validation block, so incorporating a
tracing::debug!
call—as suggested—is indeed a valuable improvement for debugging.
- File: src/app/fiat_sent.rs (lines 25-33) lacks a logging statement before returning the error for an invalid pubkey.
- Suggestion: Add a logging statement to capture the expected pubkey and the supplied value.
🏁 Scripts executed
The following scripts were executed for the analysis:
Error: No shell scripts or web queries found
Script:
#!/bin/bash rg "tracing::debug" src/app/fiat_sent.rs -n .Length of output: 45
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
src/app/release.rs (1)
243-272
: Enhance payment status handling.The payment status handling could be more robust:
- Consider handling intermediate states like
InFlight
- Add timeout handling for stuck payments
- Log payment amounts for better debugging
if let Ok(status) = PaymentStatus::try_from(msg.payment.status) { match status { PaymentStatus::Succeeded => { + info!( + "Order Id {}: Invoice with hash: {} paid! Amount: {}", + order.id, msg.payment.payment_hash, msg.payment.value + ); let _ = payment_success(&mut order, buyer_pubkey, &my_keys, request_id).await; } PaymentStatus::Failed => { info!( - "Order Id {}: Invoice with hash: {} has failed!", + "Order Id {}: Invoice with hash: {} has failed! Amount: {}", - order.id, msg.payment.payment_hash + order.id, msg.payment.payment_hash, msg.payment.value ); // Mark payment as failed if let Ok(failed_payment) = check_failure_retries(&order, request_id).await { info!( "Order id {} has {} failed payments retries", failed_payment.id, failed_payment.payment_attempts ); } } + PaymentStatus::InFlight => { + info!( + "Order Id {}: Payment in flight. Hash: {}, Amount: {}", + order.id, msg.payment.payment_hash, msg.payment.value + ); + } _ => {} } }
🧹 Nitpick comments (2)
src/app/release.rs (2)
32-34
: Consider using the?
operator for cleaner error handling.The error mapping can be simplified using the
?
operator with a type conversion implementation.- let pool = db::connect() - .await - .map_err(|cause| MostroInternalErr(ServiceError::DbAccessError(cause.to_string())))?; + let pool = db::connect().await.map_err(|e| e.into())?;
175-188
: Consider using an enum for trade roles.The repeated checks against creator_pubkey could be replaced with an enum to improve type safety and readability.
enum TradeRole { Seller, Buyer, } impl Order { fn get_trade_role(&self) -> TradeRole { if &self.creator_pubkey == self.seller_pubkey.as_ref().unwrap() { TradeRole::Seller } else { TradeRole::Buyer } } }
let pool = db::connect().await?; | ||
if let Ok(order) = order_updated.update(&pool).await { | ||
// Send dm to buyer to rate counterpart |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve database error handling in payment_success.
The database operations should use consistent error handling with the rest of the codebase.
- let pool = db::connect().await?;
- if let Ok(order) = order_updated.update(&pool).await {
+ let pool = db::connect()
+ .await
+ .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+ let order = order_updated
+ .update(&pool)
+ .await
+ .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
let pool = db::connect().await?; | |
if let Ok(order) = order_updated.update(&pool).await { | |
// Send dm to buyer to rate counterpart | |
let pool = db::connect() | |
.await | |
.map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?; | |
let order = order_updated | |
.update(&pool) | |
.await | |
.map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?; | |
// Send dm to buyer to rate counterpart |
// Settle seller hold invoice | ||
settle_seller_hold_invoice(event, ln_client, Action::Released, false, &order).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Atomicity is not enforced for the payment settlement operations.
After inspecting the code in src/util.rs
for the settle_seller_hold_invoice
function—and noting that the broader payment flow in src/app/release.rs
does not wrap its call in any transactional context (no use of keywords like transaction
, begin_transaction
, or commit
)—there is no evidence that hold invoice settlement and order status updates occur atomically.
- The function neither manages a transaction nor is it enclosed within a transactional block from the caller.
- This leaves scope for potential race conditions in the payment flow.
It is recommended to wrap these operations within a transaction to enforce atomicity.
🔗 Analysis chain
Verify payment settlement atomicity.
The hold invoice settlement and order status update should be atomic to prevent race conditions. Consider wrapping these operations in a transaction.
I'll open a new investigation to check if the settle_seller_hold_invoice
function and associated order update logic are wrapped in a transactional context. We need to verify whether these operations are executed atomically.
Let's search for the definition of settle_seller_hold_invoice
in the repository to see if it uses a transaction internally.
Let's inspect the definition of settle_seller_hold_invoice
and its surrounding context to verify if it includes transactional handling for atomicity.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for transaction handling in similar payment flows
ast-grep --pattern 'transaction|begin_transaction|commit'
Length of output: 59
Script:
#!/bin/bash
# Find the file that defines settle_seller_hold_invoice
rg -l "fn settle_seller_hold_invoice" .
Length of output: 55
Script:
#!/bin/bash
# Show context of settle_seller_hold_invoice function definition in src/util.rs
rg -C 20 "fn settle_seller_hold_invoice" ./src/util.rs
Length of output: 1062
Hi @grunch ,
ok starting with a draft to let you review what i am doing and see if we can really get something better in the end.
I will try to describe the big parts i am trying to do:
I DON'T want to touch any part of the logic, there are many changes but only as "cosmetics" modifications.
I will try to describe a bit more the three main points starting from errors:
errors.rs
is now insidemostro-core
and now mostro error is an enum with two variants as below:This errors enum can be splitted and updated to have more enum splitting errors in different categories, this was an old idea to have a more handwritten approach with Rust errors. You will see much more
map_err
around the code, but this is the way to do that.Now cantDo message are enqued in main loop, here the part in
app.rs
where the error messages are queued:There is dequeue in
scheduler.rs
that checks every second and in case dequeues messages. This has a nice effect on many part of the code like here intake_sell.rs
Just returning the error should automatically enqueue the message in main loop, and basically after max 1s scheduler will clean queue....
Finally compiles, all the work in these days was related to add other helpers in
mostro-core
and compiling and started testing, did some basic testing:Will work for other testing in the next days, will make this PR official so rabbit can sniff it and see what he sees, also if it's quite big.
Then @grunch and @Catrya please use your eyes to check everything and see if you like my modifications, still a lot of room, maybe start with takesell, takebuy and order files and check if they seem more ordered now.
Note: you need to use the same
error-manage
branch for mostro-core to compile.Now let's make rabbit speak...
Summary by CodeRabbit
Summary by CodeRabbit
New Features
Refactor
Chores