soroban_cli/commands/network/
settings.rs

1use crate::config::network;
2use crate::print::Print;
3use crate::{commands::global, config};
4use semver::Version;
5use stellar_xdr::curr::{
6    ConfigSettingId, ConfigUpgradeSet, LedgerEntryData, LedgerKey, LedgerKeyConfigSetting, Limits,
7    WriteXdr as _,
8};
9
10#[derive(thiserror::Error, Debug)]
11pub enum Error {
12    #[error(transparent)]
13    Config(#[from] config::Error),
14    #[error(transparent)]
15    Network(#[from] network::Error),
16    #[error(transparent)]
17    Xdr(#[from] stellar_xdr::curr::Error),
18    #[error(transparent)]
19    Serde(#[from] serde_json::Error),
20    #[error(transparent)]
21    Rpc(#[from] soroban_rpc::Error),
22    #[error(transparent)]
23    Semver(#[from] semver::Error),
24}
25
26#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, clap::ValueEnum, Default)]
27pub enum OutputFormat {
28    /// XDR (`ConfigUpgradeSet` type)
29    Xdr,
30    /// JSON, XDR-JSON of the `ConfigUpgradeSet` XDR type
31    #[default]
32    Json,
33    /// JSON formatted, XDR-JSON of the `ConfigUpgradeSet` XDR type
34    JsonFormatted,
35}
36
37#[derive(Debug, clap::Parser, Clone)]
38#[group(skip)]
39pub struct Cmd {
40    #[command(flatten)]
41    pub config: config::ArgsLocatorAndNetwork,
42    /// Include internal config settings that are not upgradeable and are internally maintained by
43    /// the network
44    #[arg(long)]
45    pub internal: bool,
46    /// Format of the output
47    #[arg(long, default_value = "json")]
48    pub output: OutputFormat,
49}
50
51impl Cmd {
52    pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
53        let print = Print::new(global_args.quiet);
54        let rpc = self.config.get_network()?.rpc_client()?;
55
56        // If the network protocol version is ahead of the XDR version (which tracks the protocol
57        // version), there could be config settings defined in the newer protocol version that the
58        // CLI doesn't know about. Warn, because the output of this command might provide an
59        // incomplete view of the network's config settings.
60        let network_version = rpc.get_version_info().await?.protocol_version;
61        let self_version = Version::parse(stellar_xdr::VERSION.pkg)?.major;
62        if self_version < network_version.into() {
63            print.warnln(format!("Network protocol version is {network_version} but the stellar-cli supports {self_version}. The config fetched may not represent the complete config settings for the network. Upgrade the stellar-cli."));
64        }
65
66        // Collect the ledger entries for all the config settings.
67        let keys = ConfigSettingId::variants()
68            .into_iter()
69            .filter(|id| match id {
70                // Internally maintained settings that a network validator cannot vote to change
71                // are not output by this command unless the internal option is specified.
72                ConfigSettingId::LiveSorobanStateSizeWindow | ConfigSettingId::EvictionIterator => {
73                    self.internal
74                }
75                // All other configs can be modified by network upgrades and are always output.
76                _ => true,
77            })
78            .map(|id| {
79                LedgerKey::ConfigSetting(LedgerKeyConfigSetting {
80                    config_setting_id: id,
81                })
82            })
83            .collect::<Vec<_>>();
84        let settings = rpc
85            .get_full_ledger_entries(&keys)
86            .await?
87            .entries
88            .into_iter()
89            .filter_map(|e| match e.val {
90                LedgerEntryData::ConfigSetting(setting) => Some(setting),
91                _ => None,
92            })
93            .collect::<Vec<_>>();
94
95        let config_upgrade_set = ConfigUpgradeSet {
96            updated_entry: settings.try_into().unwrap(),
97        };
98        match self.output {
99            OutputFormat::Xdr => println!("{}", config_upgrade_set.to_xdr_base64(Limits::none())?),
100            OutputFormat::Json => println!("{}", serde_json::to_string(&config_upgrade_set)?),
101            OutputFormat::JsonFormatted => {
102                println!("{}", serde_json::to_string_pretty(&config_upgrade_set)?);
103            }
104        }
105        Ok(())
106    }
107}