soroban_cli/commands/network/
settings.rs

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