Skip to content

Commit f59835a

Browse files
authored
forc-run debugger integration (#7337)
## Description Added a `--debug` flag to `forc run` with the same behavior as `forc call`'s as implemented in #7323. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [ ] I have requested a review from the relevant team or maintainers.
1 parent f036d4c commit f59835a

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

forc-plugins/forc-client/src/cmd/run.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ pub struct Command {
5555
/// Arguments to pass into main function with forc run.
5656
#[clap(long)]
5757
pub args: Option<Vec<String>>,
58+
/// Start interactive debugger after transaction execution
59+
#[clap(long, help_heading = "DEBUG")]
60+
pub debug: bool,
5861

5962
#[clap(flatten)]
6063
pub experimental: sway_features::CliFields,

forc-plugins/forc-client/src/op/run/mod.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use anyhow::{anyhow, bail, Context, Result};
1111
use forc_pkg::{self as pkg, fuel_core_not_running, PackageManifestFile};
1212
use forc_tracing::println_warning;
1313
use forc_util::tx_utils::format_log_receipts;
14+
use fuel_abi_types::abi::program::ProgramABI;
1415
use fuel_core_client::client::FuelClient;
1516
use fuel_tx::{ContractId, Transaction};
1617
use fuels::{
@@ -164,11 +165,17 @@ pub async fn run_pkg(
164165
info!("{:?}", tx);
165166
Ok(RanScript { receipts: vec![] })
166167
} else {
168+
let program_abi = match &compiled.program_abi {
169+
sway_core::asm_generation::ProgramABI::Fuel(abi) => Some(abi),
170+
_ => None,
171+
};
167172
let receipts = try_send_tx(
168173
node_url.as_str(),
169174
&tx.into(),
170175
command.pretty_print,
171176
command.simulate,
177+
command.debug,
178+
program_abi,
172179
)
173180
.await?;
174181
Ok(RanScript { receipts })
@@ -180,13 +187,15 @@ async fn try_send_tx(
180187
tx: &Transaction,
181188
pretty_print: bool,
182189
simulate: bool,
190+
debug: bool,
191+
abi: Option<&ProgramABI>,
183192
) -> Result<Vec<fuel_tx::Receipt>> {
184193
let client = FuelClient::new(node_url)?;
185194

186195
match client.health().await {
187196
Ok(_) => timeout(
188197
Duration::from_millis(TX_SUBMIT_TIMEOUT_MS),
189-
send_tx(&client, tx, pretty_print, simulate),
198+
send_tx(&client, tx, pretty_print, simulate, debug, abi),
190199
)
191200
.await
192201
.with_context(|| format!("timeout waiting for {:?} to be included in a block", tx))?,
@@ -199,6 +208,8 @@ async fn send_tx(
199208
tx: &Transaction,
200209
pretty_print: bool,
201210
simulate: bool,
211+
debug: bool,
212+
abi: Option<&ProgramABI>,
202213
) -> Result<Vec<fuel_tx::Receipt>> {
203214
let outputs = {
204215
if !simulate {
@@ -229,9 +240,61 @@ async fn send_tx(
229240
if !outputs.is_empty() {
230241
info!("{}", format_log_receipts(&outputs, pretty_print)?);
231242
}
243+
if debug {
244+
start_debug_session(client, tx, abi).await?;
245+
}
232246
Ok(outputs)
233247
}
234248

249+
/// Starts an interactive debugging session with the given transaction
250+
async fn start_debug_session(
251+
fuel_client: &FuelClient,
252+
tx: &fuel_tx::Transaction,
253+
program_abi: Option<&ProgramABI>,
254+
) -> Result<()> {
255+
// Create debugger instance from the existing fuel client
256+
let mut debugger = forc_debug::debugger::Debugger::from_client(fuel_client.clone())
257+
.await
258+
.map_err(|e| anyhow!("Failed to create debugger: {e}"))?;
259+
260+
// Create temporary files for transaction and ABI (auto-cleaned when dropped)
261+
let mut tx_file = tempfile::Builder::new()
262+
.suffix(".json")
263+
.tempfile()
264+
.map_err(|e| anyhow!("Failed to create temp transaction file: {e}"))?;
265+
serde_json::to_writer_pretty(&mut tx_file, tx)
266+
.map_err(|e| anyhow!("Failed to write transaction to temp file: {e}"))?;
267+
268+
let mut abi_file = tempfile::Builder::new()
269+
.suffix(".json")
270+
.tempfile()
271+
.map_err(|e| anyhow!("Failed to create temp ABI file: {e}"))?;
272+
273+
let tx_cmd = if let Some(abi) = program_abi {
274+
serde_json::to_writer_pretty(&mut abi_file, &abi)
275+
.map_err(|e| anyhow!("Failed to write ABI to temp file: {e}"))?;
276+
277+
// Prepare the start_tx command string for the CLI
278+
format!(
279+
"start_tx {} {}",
280+
tx_file.path().to_string_lossy(),
281+
abi_file.path().to_string_lossy()
282+
)
283+
} else {
284+
// Prepare the start_tx command string for the CLI
285+
format!("start_tx {}", tx_file.path().to_string_lossy())
286+
};
287+
288+
// Start the interactive CLI session with the prepared command
289+
let mut cli = forc_debug::cli::Cli::new()
290+
.map_err(|e| anyhow!("Failed to create debug CLI interface: {e}"))?;
291+
cli.run(&mut debugger, Some(tx_cmd))
292+
.await
293+
.map_err(|e| anyhow!("Interactive debugging session failed: {e}"))?;
294+
295+
Ok(())
296+
}
297+
235298
fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts {
236299
pkg::BuildOpts {
237300
pkg: pkg::PkgOpts {

0 commit comments

Comments
 (0)