Skip to content

Commit 976706a

Browse files
authored
Merge pull request #2146 from get10101/chore/add-emergency-kit-to-rollback-channel-state
chore(emergency kit): Add option to rollback channel to last stable state
2 parents c9dab5f + e3a68bc commit 976706a

File tree

5 files changed

+91
-5
lines changed

5 files changed

+91
-5
lines changed

coordinator/src/admin.rs

+47-3
Original file line numberDiff line numberDiff line change
@@ -405,18 +405,18 @@ pub async fn close_channel(
405405
}
406406

407407
#[derive(Debug, Deserialize)]
408-
pub struct DeleteDlcChannel {
408+
pub struct Confirmation {
409409
#[serde(default, deserialize_with = "empty_string_as_none")]
410410
i_know_what_i_am_doing: Option<bool>,
411411
}
412412

413413
/// This function deletes a DLC channel from our database irreversible!
414414
/// If you want to close a channel instead, use `close_channel`
415415
#[instrument(skip_all, err(Debug))]
416-
pub async fn delete_dlc_channels(
416+
pub async fn delete_dlc_channel(
417417
Path(channel_id_string): Path<String>,
418418
State(state): State<Arc<AppState>>,
419-
Query(params): Query<DeleteDlcChannel>,
419+
Query(params): Query<Confirmation>,
420420
) -> Result<(), AppError> {
421421
if !params.i_know_what_i_am_doing.unwrap_or_default() {
422422
let error_message =
@@ -447,6 +447,50 @@ pub async fn delete_dlc_channels(
447447
Ok(())
448448
}
449449

450+
/// This function attempts to roll back a DLC channel to the last stable state!
451+
/// The action is irreversible, only use if you know what you are doing!
452+
#[instrument(skip_all, err(Debug))]
453+
pub async fn roll_back_dlc_channel(
454+
Path(channel_id_string): Path<String>,
455+
State(state): State<Arc<AppState>>,
456+
Query(params): Query<Confirmation>,
457+
) -> Result<(), AppError> {
458+
if !params.i_know_what_i_am_doing.unwrap_or_default() {
459+
let error_message =
460+
"Looks like you don't know what you are doing! Go and ask your supervisor for help!";
461+
tracing::warn!(error_message);
462+
return Err(AppError::BadRequest(error_message.to_string()));
463+
}
464+
465+
let channel_id = parse_dlc_channel_id(&channel_id_string)
466+
.map_err(|_| AppError::BadRequest("Provided channel ID was invalid".to_string()))?;
467+
468+
tracing::info!(channel_id = %channel_id_string, "Attempting to roll back dlc channel to last stable state");
469+
470+
let channel = state
471+
.node
472+
.inner
473+
.get_dlc_channel_by_id(&channel_id)
474+
.map_err(|e| AppError::BadRequest(format!("Couldn't find channel. {e:#}")))?;
475+
if let Channel::Signed(signed_channel) = channel {
476+
state
477+
.node
478+
.inner
479+
.roll_back_channel(&signed_channel)
480+
.map_err(|e| {
481+
AppError::InternalServerError(format!("Failed to roll back channel. {e:#}"))
482+
})?
483+
} else {
484+
return Err(AppError::BadRequest(
485+
"It's only possible to rollback a channel in state signed".to_string(),
486+
));
487+
}
488+
489+
tracing::info!(channel_id = %channel_id_string, "Rolled back dlc channel");
490+
491+
Ok(())
492+
}
493+
450494
#[instrument(skip_all, err(Debug))]
451495
pub async fn sign_message(
452496
Path(msg): Path<String>,

coordinator/src/routes.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::admin::close_channel;
22
use crate::admin::collaborative_revert;
33
use crate::admin::connect_to_peer;
4-
use crate::admin::delete_dlc_channels;
4+
use crate::admin::delete_dlc_channel;
55
use crate::admin::get_balance;
66
use crate::admin::get_fee_rate_estimation;
77
use crate::admin::get_utxos;
88
use crate::admin::is_connected;
99
use crate::admin::list_dlc_channels;
1010
use crate::admin::list_on_chain_transactions;
1111
use crate::admin::list_peers;
12+
use crate::admin::roll_back_dlc_channel;
1213
use crate::admin::sign_message;
1314
use crate::backup::SledBackup;
1415
use crate::campaign::post_push_campaign;
@@ -170,7 +171,11 @@ pub fn router(
170171
.route("/api/admin/dlc_channels", get(list_dlc_channels))
171172
.route(
172173
"/api/admin/dlc_channels/:channel_id",
173-
delete(delete_dlc_channels),
174+
delete(delete_dlc_channel),
175+
)
176+
.route(
177+
"/api/admin/dlc_channels/rollback/:channel_id",
178+
post(roll_back_dlc_channel),
174179
)
175180
.route("/api/admin/transactions", get(list_on_chain_transactions))
176181
.route("/api/admin/sign/:msg", get(sign_message))

mobile/lib/common/settings/emergency_kit_screen.dart

+19
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,25 @@ class _EmergencyKitScreenState extends State<EmergencyKitScreen> {
181181
goRouter.pop();
182182
}),
183183
const SizedBox(height: 30),
184+
EmergencyKitButton(
185+
icon: const Icon(FontAwesomeIcons.backwardStep),
186+
title: "Rollback channel state",
187+
onPressed: () async {
188+
final messenger = ScaffoldMessenger.of(context);
189+
final orderChangeNotifier = context.read<OrderChangeNotifier>();
190+
final goRouter = GoRouter.of(context);
191+
192+
try {
193+
await rust.api.rollBackChannelState();
194+
await orderChangeNotifier.initialize();
195+
showSnackBar(messenger, "Successfully rolled back channel state");
196+
} catch (e) {
197+
showSnackBar(messenger, "Failed to rollback channel state. Error: $e");
198+
}
199+
200+
goRouter.pop();
201+
}),
202+
const SizedBox(height: 30),
184203
Visibility(
185204
visible: config.network == "regtest",
186205
child: EmergencyKitButton(

mobile/native/src/api.rs

+7
Original file line numberDiff line numberDiff line change
@@ -819,3 +819,10 @@ pub fn get_new_random_name() -> SyncReturn<String> {
819819
pub async fn update_nickname(nickname: String) -> Result<()> {
820820
users::update_username(nickname).await
821821
}
822+
823+
pub fn roll_back_channel_state() -> Result<()> {
824+
tracing::warn!(
825+
"Executing emergency kit! Attempting to rollback channel state to last stable state"
826+
);
827+
ln_dlc::roll_back_channel_state()
828+
}

mobile/native/src/ln_dlc/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1057,3 +1057,14 @@ fn confirmation_status_to_status_and_timestamp(
10571057

10581058
(status, timestamp.unix_timestamp() as u64)
10591059
}
1060+
1061+
pub fn roll_back_channel_state() -> Result<()> {
1062+
let node = state::get_node();
1063+
1064+
let counterparty_pubkey = config::get_coordinator_info().pubkey;
1065+
let signed_channel = node
1066+
.inner
1067+
.get_signed_channel_by_trader_id(counterparty_pubkey)?;
1068+
1069+
node.inner.roll_back_channel(&signed_channel)
1070+
}

0 commit comments

Comments
 (0)