Skip to content

Commit e3a68bc

Browse files
committed
chore(emergency kit): Add option to rollback channel to last stable state
1 parent bb9ff96 commit e3a68bc

File tree

5 files changed

+86
-0
lines changed

5 files changed

+86
-0
lines changed

coordinator/src/admin.rs

+44
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,50 @@ pub async fn delete_dlc_channel(
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

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ 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;
@@ -172,6 +173,10 @@ pub fn router(
172173
"/api/admin/dlc_channels/:channel_id",
173174
delete(delete_dlc_channel),
174175
)
176+
.route(
177+
"/api/admin/dlc_channels/rollback/:channel_id",
178+
post(roll_back_dlc_channel),
179+
)
175180
.route("/api/admin/transactions", get(list_on_chain_transactions))
176181
.route("/api/admin/sign/:msg", get(sign_message))
177182
.route("/api/admin/connect", post(connect_to_peer))

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)