Skip to content
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

Rewrite channel actor state tlc operations #341

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cch/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ impl CchActor {
}

order.channel_id = Some(tlc_notification.channel_id);
order.tlc_id = Some(tlc_notification.tlc.id.into());
order.tlc_id = Some(tlc_notification.tlc.tlc_id.into());
state.orders_db.update_send_btc_order(order.clone()).await?;

let req = routerrpc::SendPaymentRequest {
Expand Down Expand Up @@ -593,7 +593,7 @@ impl CchActor {
expiry: now_timestamp_as_millis_u64()
+ self.config.ckb_final_tlc_expiry_delta,
hash_algorithm: HashAlgorithm::Sha256,
peeled_onion_packet: None,
onion_packet: None,
previous_tlc: None,
},
rpc_reply,
Expand Down
2 changes: 1 addition & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub enum Error {
#[error("Send payment error: {0}")]
SendPaymentError(String),
#[error("Send payment first hop error: {0}")]
SendPaymentFirstHopError(String),
SendPaymentFirstHopError(String, bool),
#[error("InvalidParameter: {0}")]
InvalidParameter(String),
#[error("Network Graph error: {0}")]
Expand Down
2,072 changes: 1,163 additions & 909 deletions src/fiber/channel.rs

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/fiber/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ impl InternalResult {
| TlcErrorCode::InvalidOnionPayload => {
self.fail_node(nodes, 1);
}
TlcErrorCode::IncorrectOrUnknownPaymentDetails | TlcErrorCode::InvoiceExpired => {
need_to_retry = false;
}
_ => {
// we can not penalize our own node, the whole payment session need to retry
debug!("first hop failed with error: {:?}", tlc_err);
Expand Down Expand Up @@ -286,6 +289,10 @@ impl InternalResult {
self.fail_range_pairs(nodes, 0, index - 1);
}
}
TlcErrorCode::IncorrectOrUnknownPaymentDetails | TlcErrorCode::InvoiceExpired => {
need_to_retry = false;
self.succeed_range_pairs(nodes, 0, index - 1);
}
_ => {
self.fail_node(nodes, index);
}
Expand Down
81 changes: 60 additions & 21 deletions src/fiber/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ pub enum NetworkServiceEvent {
ChannelCreated(PeerId, Hash256),
// A outgoing channel is pending to be accepted.
ChannelPendingToBeAccepted(PeerId, Hash256),
// A AddTlc peer message processed with failure
AddTlcFailed(PeerId, Hash256, TlcErr),
// The channel is ready to use (with funding transaction confirmed
// and both parties sent ChannelReady messages).
ChannelReady(PeerId, Hash256, OutPoint),
Expand Down Expand Up @@ -600,6 +602,9 @@ pub enum NetworkActorEvent {

// A tlc remove message is received. (payment_hash, remove_tlc)
TlcRemoveReceived(Hash256, RemoveTlcReason),

// A payment need to retry
RetrySendPayment(Hash256),
}

#[derive(Copy, Clone, Debug)]
Expand Down Expand Up @@ -1257,9 +1262,12 @@ where
}
NetworkActorEvent::TlcRemoveReceived(payment_hash, remove_tlc_reason) => {
// When a node is restarted, RemoveTLC will also be resent if necessary
self.on_remove_tlc_event(state, payment_hash, remove_tlc_reason)
self.on_remove_tlc_event(myself, state, payment_hash, remove_tlc_reason)
.await;
}
NetworkActorEvent::RetrySendPayment(payment_hash) => {
let _ = self.try_payment_session(myself, state, payment_hash).await;
}
}
Ok(())
}
Expand Down Expand Up @@ -1588,7 +1596,7 @@ where
let _ = reply.send(signature);
}
NetworkActorCommand::SendPayment(payment_request, reply) => {
match self.on_send_payment(state, payment_request).await {
match self.on_send_payment(myself, state, payment_request).await {
Ok(payment) => {
let _ = reply.send(Ok(payment));
}
Expand Down Expand Up @@ -2179,7 +2187,7 @@ where
payment_hash: info.payment_hash,
expiry: info.expiry,
hash_algorithm: info.hash_algorithm,
peeled_onion_packet: Some(peeled_onion_packet),
onion_packet: peeled_onion_packet.next.clone(),
previous_tlc,
},
rpc_reply,
Expand Down Expand Up @@ -2209,6 +2217,7 @@ where

async fn on_remove_tlc_event(
&self,
myself: ActorRef<NetworkActorMessage>,
state: &mut NetworkActorState<S>,
payment_hash: Hash256,
reason: RemoveTlcReason,
Expand All @@ -2231,7 +2240,9 @@ where
.await
.record_payment_fail(&payment_session, error_detail.clone());
if need_to_retry {
let res = self.try_payment_session(state, payment_session).await;
let res = self
.try_payment_session(myself, state, payment_session.payment_hash())
.await;
if res.is_err() {
debug!("Failed to retry payment session: {:?}", res);
}
Expand Down Expand Up @@ -2363,7 +2374,7 @@ where
// This is the error implies we send payment request to the first hop failed
// graph or payment history need to update and then have a retry
self.update_graph_with_tlc_fail(&error_detail).await;
let _ = self
let need_to_retry = self
.network_graph
.write()
.await
Expand All @@ -2373,7 +2384,7 @@ where
error_detail.error_code_as_str()
);
self.set_payment_fail_with_error(payment_session, &err);
return Err(Error::SendPaymentFirstHopError(err));
return Err(Error::SendPaymentFirstHopError(err, need_to_retry));
} else {
// This expected never to be happended, to be safe, we will set the payment session to failed
let err = format!("Failed to send onion packet, got malioucious error message");
Expand All @@ -2396,13 +2407,17 @@ where

async fn try_payment_session(
&self,
myself: ActorRef<NetworkActorMessage>,
state: &mut NetworkActorState<S>,
mut payment_session: PaymentSession,
payment_hash: Hash256,
) -> Result<PaymentSession, Error> {
let Some(mut payment_session) = self.store.get_payment_session(payment_hash) else {
return Err(Error::InvalidParameter(payment_hash.to_string()));
};

let payment_data = payment_session.request.clone();
while payment_session.can_retry() {
if payment_session.can_retry() {
payment_session.retried_times += 1;

let hops_info = self
.build_payment_route(&mut payment_session, &payment_data)
.await?;
Expand All @@ -2412,27 +2427,49 @@ where
.await
{
Ok(payment_session) => return Ok(payment_session),
Err(Error::SendPaymentFirstHopError(_)) => {
// we will retry the payment session
continue;
Err(Error::SendPaymentFirstHopError(err, need_retry)) => {
if need_retry {
// If this is the first hop error, like the WaitingTlcAck error,
// we will just retry later, return Ok here for letting endpoint user
// know payment session is created successfully
myself.send_after(Duration::from_millis(500), move || {
NetworkActorMessage::new_event(NetworkActorEvent::RetrySendPayment(
payment_hash,
))
});
return Ok(payment_session);
} else {
return Err(Error::SendPaymentError(err));
}
}
Err(e) => {
// we will retry the payment session,
// but we need to retry later to let the actor to process failure,
// so that we can make different choice for later try
let payment_hash = payment_data.payment_hash;
myself.send_after(Duration::from_millis(500), move || {
NetworkActorMessage::new_event(NetworkActorEvent::RetrySendPayment(
payment_hash,
))
});
debug!("send payment error: {:?}", e);
return Err(e);
}
}
} else {
let error = payment_session.last_error.clone().unwrap_or_else(|| {
format!(
"Failed to send payment session: {:?}, retried times: {}",
payment_data.payment_hash, payment_session.retried_times
)
});
return Err(Error::SendPaymentError(error));
}

let error = payment_session.last_error.clone().unwrap_or_else(|| {
format!(
"Failed to send payment session: {:?}, retried times: {}",
payment_data.payment_hash, payment_session.retried_times
)
});
return Err(Error::SendPaymentError(error));
}

async fn on_send_payment(
&self,
myself: ActorRef<NetworkActorMessage>,
state: &mut NetworkActorState<S>,
payment_request: SendPaymentCommand,
) -> Result<SendPaymentResponse, Error> {
Expand Down Expand Up @@ -2467,7 +2504,9 @@ where

let payment_session = PaymentSession::new(payment_data, 5);
self.store.insert_payment_session(payment_session.clone());
let session = self.try_payment_session(state, payment_session).await?;
let session = self
.try_payment_session(myself, state, payment_session.payment_hash())
.await?;
return Ok(session.into());
}
}
Expand Down
Loading
Loading