soroban_cli/commands/tx/
simulate.rs

1use crate::{
2    assembled::{simulate_and_assemble_transaction, Assembled},
3    xdr::{self, TransactionEnvelope, WriteXdr},
4};
5use async_trait::async_trait;
6use std::ffi::OsString;
7
8use crate::commands::{config, global, NetworkRunnable};
9
10#[derive(thiserror::Error, Debug)]
11pub enum Error {
12    #[error(transparent)]
13    XdrArgs(#[from] super::xdr::Error),
14    #[error(transparent)]
15    Config(#[from] super::super::config::Error),
16    #[error(transparent)]
17    Rpc(#[from] crate::rpc::Error),
18    #[error(transparent)]
19    Xdr(#[from] xdr::Error),
20    #[error(transparent)]
21    Network(#[from] config::network::Error),
22}
23
24/// Command to simulate a transaction envelope via rpc
25/// e.g. `stellar tx simulate file.txt` or `cat file.txt | stellar tx simulate`
26#[derive(Debug, clap::Parser, Clone, Default)]
27#[group(skip)]
28pub struct Cmd {
29    /// Base-64 transaction envelope XDR or file containing XDR to decode, or stdin if empty
30    #[arg()]
31    pub tx_xdr: Option<OsString>,
32
33    #[clap(flatten)]
34    pub config: config::Args,
35
36    /// Allow this many extra instructions when budgeting resources during transaction simulation
37    #[arg(long)]
38    pub instruction_leeway: Option<u64>,
39}
40
41impl Cmd {
42    pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
43        let res = self
44            .run_against_rpc_server(Some(global_args), Some(&self.config))
45            .await?;
46        let tx_env: TransactionEnvelope = res.transaction().clone().into();
47        println!("{}", tx_env.to_xdr_base64(xdr::Limits::none())?);
48        Ok(())
49    }
50}
51
52#[async_trait]
53impl NetworkRunnable for Cmd {
54    type Error = Error;
55
56    type Result = Assembled;
57    async fn run_against_rpc_server(
58        &self,
59        _: Option<&global::Args>,
60        config: Option<&config::Args>,
61    ) -> Result<Self::Result, Self::Error> {
62        let config = config.unwrap_or(&self.config);
63        let network = config.get_network()?;
64        let client = network.rpc_client()?;
65        let tx = super::xdr::unwrap_envelope_v1(super::xdr::tx_envelope_from_input(&self.tx_xdr)?)?;
66        let resource_config = self
67            .instruction_leeway
68            .map(|instruction_leeway| soroban_rpc::ResourceConfig { instruction_leeway });
69        let tx = simulate_and_assemble_transaction(&client, &tx, resource_config).await?;
70        Ok(tx)
71    }
72}