diff --git a/xc-tool/Cargo.lock b/xc-tool/Cargo.lock new file mode 100644 index 00000000..2a90d1b7 --- /dev/null +++ b/xc-tool/Cargo.lock @@ -0,0 +1,215 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "clap" +version = "4.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "os_str_bytes" +version = "6.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyth-xc-tool" +version = "0.1.0" +dependencies = [ + "clap", + "shell-words", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/xc-tool/Cargo.toml b/xc-tool/Cargo.toml new file mode 100644 index 00000000..cf0674f7 --- /dev/null +++ b/xc-tool/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "pyth-xc-tool" +authors = ["Pyth Network Contributors"] +description = "The cross-chain priest for the Pyth oracle (it knows all the rituals)" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = {version = "4.0", features = ["derive", "cargo"]} +shell-words = "1.1.0" diff --git a/xc-tool/src/cli.rs b/xc-tool/src/cli.rs new file mode 100644 index 00000000..3bbea6c0 --- /dev/null +++ b/xc-tool/src/cli.rs @@ -0,0 +1,41 @@ +use clap::{Parser, Subcommand, ValueEnum}; + +#[derive(Parser)] +#[clap( + about = "Pyth Tool - the admin swiss army knife", + author = "Pyth Network Contributors" +)] +pub struct Cli { + #[clap(subcommand)] + pub action: Action, + /// Mainnet/testnet + #[clap(default_value = "testnet")] + pub net: Net, +} + +/// This struct helps reuse action parsing logic for interactive mode. +#[derive(Parser)] +#[clap( + about = "Pyth Tool - the admin swiss army knife", + author = "Pyth Network Contributors" +)] +pub struct CliInteractive { + #[clap(subcommand)] + pub action: Action, +} + +#[derive(Subcommand, PartialEq)] +pub enum Action { + #[clap(about = "Attempt sanity-check access for all known blockchains")] + PingAll, + #[clap(about = "Fires up a repl letting user directly perform all other actions")] + Interactive, +} + +/// For most chains, we pick a production blockchain network and a +/// testing one, closely following Wormhole's choices. +#[derive(ValueEnum, Clone)] +pub enum Net { + Mainnet, + Testnet, +} diff --git a/xc-tool/src/main.rs b/xc-tool/src/main.rs new file mode 100644 index 00000000..fe8b70ab --- /dev/null +++ b/xc-tool/src/main.rs @@ -0,0 +1,72 @@ +mod cli; +mod util; + +use clap::Parser; + +use std::io::{self, Write}; + +use cli::{Action, Cli, CliInteractive}; + +use util::ErrBox; + +pub const PROMPT: &'static str = concat!(env!("CARGO_PKG_NAME"), "> "); + +fn main() -> Result<(), ErrBox> { + let cli = Cli::parse(); + + // Handle interactive mode separately + if cli.action == Action::Interactive { + start_cli_interactive(cli)?; + } else { + handle_action_noninteractive(&cli)?; + } + Ok(()) +} + +pub fn start_cli_interactive(mut cli: Cli) -> Result<(), ErrBox> { + let stdin = io::stdin(); + loop { + print!("{}", PROMPT); + io::stdout().flush()?; + let mut ln = String::new(); + stdin.read_line(&mut ln)?; + + if ln.trim().is_empty() { + continue; + } + + match shell_words::split(&ln) + .map_err(|e| -> ErrBox { e.into() }) + .and_then(|mut shell_split| { + // Trick clap into thinking there's a binary name + let mut with_name = vec!["".to_owned()]; + with_name.append(&mut shell_split); + Ok(CliInteractive::try_parse_from(with_name)?) + }) + .and_then(|cmd| { + // We just swap out the action, preserving the top-level arguments + cli.action = cmd.action; + Ok(handle_action_noninteractive(&cli)?) + }) { + Err(e) => { + println!("Could not understand that! Error:\n{}", e.to_string()); + } + Ok(()) => {} + }; + } +} + +/// The following code is reused by interactive mode. Interactive mode +/// is assumed to already be detected at top-level in main, making it an invalid action. +pub fn handle_action_noninteractive(cli: &Cli) -> Result<(), ErrBox> { + match &cli.action { + // It makes no sense starting interactive already inside it + Action::Interactive => { + return Err(format!("Bruh...?").into()); + } + Action::PingAll => { + println!("Pinging all blockchains..."); + } + } + Ok(()) +} diff --git a/xc-tool/src/util.rs b/xc-tool/src/util.rs new file mode 100644 index 00000000..223fddb2 --- /dev/null +++ b/xc-tool/src/util.rs @@ -0,0 +1 @@ +pub type ErrBox = Box;